วันพุธที่ 13 พฤษภาคม พ.ศ. 2563

การสร้าง Form ใน Python

Python มี tool ดีๆ มาก แต่มักจะเป็น Command line จะให้มี User Interface มี Tool ที่ง่ายๆ ได้แก่ tkinter

วิธีใช้
ใช่ messagebox

from tkinter import messagebox

messagebox.showinfo('Title','hello world')


จะแสดงเป็น Message box



ถ้าต้องการ Form และมี Response

from tkinter import *
from tkinter import messagebox
from tkinter import ttk
window = Tk()
window.title("Welcome to TutorialsPoint")
window.geometry('400x400')
lName = Label(window ,text = "Name").grid(row = 0,column = 0)
name = Entry(window,width=10)
name.grid(row = 0,column = 1)
def clicked():
  messagebox.showinfo('ok',name.get())
btn = ttk.Button(window ,text="Submit",command=clicked).grid(row=4,column=0)
window.mainloop()

สังเกตุที่ def clicked() จะเป็น Event ใน ttk.Button
เมื่อกดจะเกิด Pop up





วันอังคารที่ 14 เมษายน พ.ศ. 2563

การสร้าง Dynamo Dropdown Node

Dropdown  Node ของ Dynamo ทำให้ผู้ใช้งาน ง่ายขึ้นในการเลือก Option ต่างๆ แต่การสร้าง ต้องทำเป็น Class คนละวิธีกับ การสร้าง Function Node ข้อแนะนำควรจะใช้ Dynamo Engine 2 และจำเป็นต้องวาง packages และ bin ใน Folder Default ของ Dynamo เท่านั้น ไม่นั้น จะไม่ทำงาน

จะมี องค์ประกอบ ได้แก่ Class ที่ต้อง Inherite จาก
DSDropDownBase
และมีองค์ประกอบ
PopulateItemsCore เพื่อใส่ค่าใน Item
และผลตัวเลือก
BuildOutputAst

ตัวอย่าง ที่ Fix bug แล้วจาก SampleDropdownUi ของ Dynamo


using System.Collections.Generic;
using CoreNodeModels;
using Dynamo.Graph.Nodes;
using Dynamo.Utilities;
using ProtoCore.AST.AssociativeAST;
using Newtonsoft.Json;

namespace SampleLibraryUI.Examples
{
    [NodeName("Drop Down Example")]
    [NodeDescription("Fixed An example drop down node.")]
    [IsDesignScriptCompatible]
    public class DropDownExample : DSDropDownBase
    {
        public DropDownExample() : base("itemA"){
              }

        // Starting with Dynamo v2.0 you must add Json constructors for all nodeModel
        // dervived nodes to support the move from an Xml to Json file format.  Failing to
        // do so will result in incorrect ports being generated upon serialization/deserialization.
        // This constructor is called when opening a Json graph. We must also pass the deserialized 
        // ports with the json constructor and then call the base class passing the ports as parameters.
        [JsonConstructor]
        public DropDownExample(IEnumerable<PortModel> inPorts, IEnumerable<PortModel> outPorts) : base("itemA", inPorts, outPorts) { }

        protected override SelectionState PopulateItemsCore(string currentSelection)
        {
            // The Items collection contains the elements
            // that appear in the list. For this example, we
            // clear the list before adding new items, but you
            // can also use the PopulateItems method to add items
            // to the list.

            Items.Clear();

            // Create a number of DynamoDropDownItem objects 
            // to store the items that we want to appear in our list.

            var newItems = new List<DynamoDropDownItem>()
            {
                new DynamoDropDownItem("Item 0", 0),
                new DynamoDropDownItem("Item 1", 1),
                new DynamoDropDownItem("Item 2",2)
            };

            Items.AddRange(newItems);

            // Set the selected index to something other
            // than -1, the default, so that your list
            // has a pre-selection.

            SelectedIndex = 0;
            return SelectionState.Restore;
        }

        public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
        {
            // Build an AST node for the type of object contained in your Items collection.
            if (Items.Count == 0 ||  SelectedIndex <0 || SelectedIndex >= Items.Count) // Bug fixed!
            {
                return new[] { AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), AstFactory.BuildNullNode()) };
            }

            var intNode = AstFactory.BuildIntNode((int)Items[SelectedIndex].Item);
            var assign = AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), intNode);
            return new List<AssociativeNode> { assign };

        }
    }
}

วันศุกร์ที่ 20 มีนาคม พ.ศ. 2563

สร้าง Node C# ใน Revit Dynamo โดยใช้ ZeroTouch

Dynamo เป็น การ Custom โปรแกรม Revit โดยใช้ Graphic Drag and Drop  โดยที่แต่ละ คำสั่งจะเป็น รูป Block ของคำสั่ง มีคนเขียน โปรแกรม เพื่อให้ Revit ทำงาน ได้ หลากหลาย มาก แต่บางอย่าง ก็ยุ่งยยาก เนื่องจาก ไม่ใช้ Program Language
การ เชื่อม Node ของ Dynamo จึงทำให้งานบางอย่างง่ายขึ้น เช่น การ Filter String Data  ที่ซับซ้อนโดยใช้ Rex หรือเชื่อมกับโปรแกรมระบบอื่นๆ
การ Custom Node ด้วย C# เคยเขียนใว้แล้วใน บทความ. https://thaibimpro.blogspot.com/2015/12/node-c-dynamo.html
ปัจจุบัน ง่ายกว่าเดิม โดยใข้ Tools ใน Visual Studio
วิธีการ
ให้ทำการ สร้าง New Project -> Class library ซึ่งจะเป็นชื่อใน Menu หมวด ของ Dynamo
เช่น. DynamoOk
จากนั้นไปที่ Tools->Nuget Package Manager->Browse-> พิมพ์ ZeroTouch จะเจอ
DynamoVisualProgramming.ZeroTouch
ติดตั้งลงใน Project ปัจจุบัน
แก้ Code สร้าง Class ตามต้องการ โดยกำหนด Namespace เป็น 2 ช่วงเช่น
<ชื่อหลัก>.<ชื่อหมวดงาน>
และ Method จะต่อ จาก <ชื่อหมวดงาน>


namespace PowerPartners.DynamoOk
{
    public static class FirstContact
    {
        public static string HelloWorld(string str)
        {
            string s = "Hello World " + str;
            return s;
        }
    }
}
Compile และ ใน Revit,Dyanamo ให้ กด add->import library จะได้ เมนู และ มี ชื่อตามรูป



เมื่อ Drag มา และทดลองใส่ String


แต่ เมนูนี้ จะหายไปเมื่อเข้าใหม่ ถ้าต้องการ ให้มันอยู่ ต้อง Register  UUID ของโปรแกรม และ สร้าง Json package ใว้ใน Dynamo Core

** note การ Set Debug ใน Visual Studio
Tools > Options… > Debugging > General > Check “Use Managed Compatibility Mode


วันพุธที่ 11 มีนาคม พ.ศ. 2563

Autocad load dotnet application ไม่ได้ จาก Network Drive

Window 10 มี Security เพิ่ม โดยไม่ให้ application เช่น Autocad ที่ ทำงานอยู่ netload โปรแกรมจาก Network Drive หรือ URL บางระบบ Domain จะ Load โปรแกรมไม่ได้ แม้แต่ Drive C:
วิธีแก้ ต้องไปเพิ่ม ข้อความนี้ ใน acad.exe.config ใน c:\program files\Autodesk\Autocad 20xx\

<configuration>
<runtime>
<loadFromRemoteSources enabled="true"/> </runtime>
...

วันอังคารที่ 10 มีนาคม พ.ศ. 2563

วิธี Debug C# Autocad dotnet ด้วย Visual Studio 2015-2017

การ Debug โปรแกรม C# ที่เขียนสำหรับ Autocad 2013-2x ด้วย Visual Studio 2015-19ทำได้ แต่ลึกลับ พอสมควร และมี ข้อจำกัด เนื่องจาก เขาไม่ต้องการให้ Debug ใน Process ของ Acad.exe ง่ายๆไม่ให้ Hack

วิธีการ
1. ต้องไปที่ Project ที่ ทำอยู่. Property Setting-> set เป็น Debug
2. Setting->start External program ให้เป็น c:\program files\Autodesk\Autocad xxxx\acad.exe
 Setting ->debug ไป เช็กที่ Enable Native Code Debugging
3. Tools->Options->Debugging
    เช็ก เอาออก Enable UI Debugging tools for XAML และ Edit and Continue
    เช็ก Managed Compatibility Mode

ReBuild all
และ กด F5 จะ run Autocad และ netload โปรแกรมใน ..\Debug\<program>.dll ก็จะเข้า Debug โปรแกรมที่ทำอยู่

วันอาทิตย์ที่ 3 พฤศจิกายน พ.ศ. 2562

ทำ Ribbon บน C# Form

การทำ Ribbon ใน C# Form จะใช้ ได้ ควรเป็น Dotnet 4.6.1 ในเลือกไปที่
Nuget Manager เลือก Ribbon WinForms



แต่มักจะมีปัญหาว่า Ribbon อาจจะไม่แสดง ใน Toolbox  ต้องไป set ใน Toolbox Show all

และเลือก Choose Items เลือก Ribbon ถ้าไม่เจอต้อง Browse Reference ไปที่ DLL




วางใน Form เลือก ลง Ribbon บนจอจะให้ใส่ Tab และ Panel และ ใส่ Button ได้ และกดสร้าง Event ได้ตามปรกติ


วันเสาร์ที่ 5 ตุลาคม พ.ศ. 2562

C# จัดการ Zip file

C# จัดการ Zip ให้ Reference system.io.compression และ system.io.compression.filesystem

ในการ List ไฟล์ใน Zip
   private void button_open_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();

            string zipPath = label1.Text;

                using (ZipArchive archive = ZipFile.OpenRead(zipPath))
            {
                foreach (ZipArchiveEntry entry in archive.Entries)
                {
                        // Gets the full path to ensure that relative segments are removed.
                        string destinationPath =  entry.FullName;
                        listBox1.Items.Add(destinationPath);
            
                }
            }
        }
ในการ Extract File ออกมา แล้ว edit ด้วย Notepad

  private void button_Edit_Click(object sender, EventArgs e)
        { // select file
            int index = listBox1.SelectedIndex;
            string sFile = listBox1.Items[index].ToString();
            // extract file
            string exPath = "c:/temp/";
            string zipPath = label1.Text;

            using (ZipArchive archive = ZipFile.OpenRead(zipPath))
            {
                foreach (ZipArchiveEntry entry in archive.Entries)
                {
                    // Gets the full path to ensure that relative segments are removed.
                    string destinationPath = exPath+entry.FullName;
                    if (entry.FullName == sFile)
                    { // extrac file

                        entry.ExtractToFile(destinationPath,true);
                        label_msg.Text = "Extract to " + destinationPath;
                        string editor = @"C:\WINDOWS\NOTEPAD.EXE";
                        Process.Start(editor, destinationPath);
                    }
                    
                }
            }
        }


ในการ Delete File เดิม และ จัดเก็บ


 private void button_Save_Click(object sender, EventArgs e)
        {
            int index = listBox1.SelectedIndex;
            string sFile = listBox1.Items[index].ToString();
            // extract file
            string exPath = "c:/temp/";
            string zipPath = label1.Text;

            using (ZipArchive archive = ZipFile.Open(zipPath, ZipArchiveMode.Update))
            {
                // delete old file
                foreach (ZipArchiveEntry entry in archive.Entries)
                {
                    // Gets the full path to ensure that relative segments are removed.
                    string destinationPath1 = exPath + entry.FullName;
                    if (entry.FullName == sFile)
                    { // extrac file
                        entry.Delete();
                        label_msg.Text = "delete zip " + sFile;
                        break;
                    }

                }

            }
            // update 
            using (ZipArchive archive = ZipFile.Open(zipPath, ZipArchiveMode.Update))
            { 
                string destinationPath = exPath + sFile;
                    archive.CreateEntryFromFile(destinationPath, sFile);
                    
                    label_msg.Text = "Zip to " + destinationPath;
                    return;
                
            }
        }