-
Postów
432 -
Dołączył
-
Ostatnia wizyta
-
Wygrane w rankingu
36
Treść opublikowana przez perlon
-
Wymiar z podziałem na "n" cześci
perlon odpowiedział(a) na kma.s temat w ZWCAD Standard i Professional
Zapewne jest możliwe, ale nie wiem jak odczytać tę właściwość. UNITS daje takie okno: W autocad jest coś takiego jak -DWGUNITS (polecenie zewnętrzne w arx) ale w ZwCAD nie zadziała. Nie wiem jaka zmienna trzyma aktualną jednostkę rysunkową. Nic innego w temacie jednostek mi nie przychodzi do głowy, chyba że nakładki, ale to inna bajka bo każda nakładka trzyma jednostki po swojemu. -
Wymiar z podziałem na "n" cześci
perlon odpowiedział(a) na kma.s temat w ZWCAD Standard i Professional
W między czasie jak jeszcze mogłem posta zedytować dorzuciłem warunek sprawdzający czy faktycznie wskazany obiekt jest wymiarem czego nie ma w podlinkowanym pliku lsp: ;c:ww1() ;[...] (if (= (cdr (assoc 0 (entget ent))) "DIMENSION") (multipledimsection (entget ent)) (princ "\nBlad: Wskazany obiekt nie jest wymiarem liniowym") ) -
Wymiar z podziałem na "n" cześci
perlon odpowiedział(a) na kma.s temat w ZWCAD Standard i Professional
A co mi tam. Napisałem rybę. Mi się też przyda (defun c:ww1 ( / ent) (while (= nil ent) (progn (prompt "\nWskaz wymiar do zmiany: ") (setq ent (car (entsel))) ) ) (if (= (cdr (assoc 0 (entget ent))) "DIMENSION") (multipledimsection (entget ent)) ) ) (defun c:ww2 ( / ) (command "_dimlinear" pause pause pause) (multipledimsection (entget (entlast))) ) (defun multipledimsection ( entlist / n section newtext) (setq n (getint "\nPodaj liczbe odcinkow: ") section (/ (cdr (assoc 42 entlist)) n) newtext (strcat "<>\\X(" (itoa n) "x" (rtos section 2 2) ")") entlist (subst (cons 1 newtext) (assoc 42 entlist) entlist) ) (entmod entlist) (princ) ) (princ) -
Wymiar z podziałem na "n" cześci
perlon odpowiedział(a) na kma.s temat w ZWCAD Standard i Professional
Taka wędka do samodzielnej przeróbki na rybę 😉 (defun c:ww ( / ent n entlist dimvalue section newtext) (while (= nil ent) (progn (prompt "\nWskaz wymiar do zmiany: ") (setq ent (car (entsel))) ) ) (setq n (getint "\nPodaj liczbe odcinkow: ") entlist (entget ent) section (/ (cdr (assoc 42 entlist)) n) newtext (strcat "<>\\X(" (itoa n) "x" (rtos section 2 2) ")") entlist (subst (cons 1 newtext) (assoc 42 entlist) entlist) ) (entmod entlist) (princ) ) -
LISP - rysowanie części/kontury.
perlon odpowiedział(a) na arexxx temat w Wsparcie programistyczne LISP i VisualLISP
Pisanie lispa bezpośrednio do okna komend to raczej słabe jest. Żadnych szans na poprawki. Zrób kolego tak: 1. Otwórz jakiś edytor tekstowy (notatnik, notepad++, cokolwiek) 2, Wpisz coś takiego (command "Line" (getpoint) (getpoint) (getpoint) (getpoint) "c") 3. Zapisz jako : d:\moj_lisp.lsp d:\ jest przykładową lokalizacją ty wybierz sobie jaką tam chcesz, moj_lisp.lsp jest nazwą pliku LSP który należy wczytać do zwcad'a. Też możesz wybrać cokolwiek byle miało rozszerzenie .LSP 4. W linii komend w zwcad'zie wpisz (load "d:\moj_lisp.lsp") 5. Wskaż cztery punkty zgodnie z podpowiedzią w linii komend 6. Masz swój pierwszy program w LISP'ie rysujący czworokąt z obiektów typu linia o wskazanych wierzchołkach 7. Wpisz do powyższego pliku taką sekwencję (setq p1 (getpoint "Wskaz punkt:")) (setq p2 (polar p1 0 100)) (setq p3 (polar p2 (/ PI 2) 100)) (setq p4 (polar p3 PI 100)) (command "Line" p1 p2 p3 p4 "c") 8. Zapisz i załaduj ponownie do zwcad'a Masz lispa który rysuje kwadrat. W pliku moj_lisp.lsp możesz dopisywać kolejne komendy, polecenia, funkcje które złożą się na jakąś sekwencję dającą oczekiwany efekt. Możesz na forum wrzucić co masz już napisane, to dasz szansę, żeby ci pomóc. -
LISP - rysowanie części/kontury.
perlon odpowiedział(a) na arexxx temat w Wsparcie programistyczne LISP i VisualLISP
Nie mówię, że się podejmę, ale chciałbym zwrócić uwagę że brakuje kilku wymiarów i wydaje mi się, że podane zależności wymiarowe na rysunku uniemożliwiają prawidłowe wykonstruowanie tego kształtu. Brakuje rozstawu wybrań na dolnej krawędzi i wysięgu wypustu. Pomijając to geometrycznie to lipa jest. Jeżeli założymy (w przybliżeniu) R = b/3 to ( b/3 - 5 ) + b/3 + b/3 + ( b/3 - 5 ) = 4b/3 - 10 = b -> b = 30; R=10 U góry jest to jedynie rozwiązanie a widać. że na dole nie da się upchnąć dwóch wybrań o promieniu R=b/3=10 nie mówiąc już o wypuście. Musisz chyba jeszcze raz przemyśleć zadanie. Oczywiście, jest możliwość, że się mylę, ale w takim razie tym bardziej nie jestem w stanie ci pomóc. -
Automatyczna numeracja
perlon odpowiedział(a) na Harry temat w Wsparcie programistyczne LISP i VisualLISP
A może to ci się nada https://kojacek.wordpress.com/2018/05/17/numerator/ -
[LISP] Tworzenie własnego menu
perlon odpowiedział(a) na swazy temat w Wsparcie programistyczne LISP i VisualLISP
Należałoby najpierw uściślić czy chodzi ci o wstążkę czyli z angielska ribbon w stylu wstążkowym interfejsu, Czy może jednak menu rozwijanie z interfejsu klasycznego to co pokazałeś na własnym zrzucie ekranu. Kwestia semantyki. Jeżeli to pierwsze to trzeba się bawić edytorem plików .cui (Tools->Customize->Customize interface) Jeżeli to drugie to poszukaj w googlu hasła autocad custom menu pull-down; i polecenia menuload Tutaj masz co nieco o tworzeniu własnego menu. https://www.afralisp.net/archive/lispa/menu1.htm http://www.thirdistudio.com.au/AutoCADmenu1.html no i oficjalna strona autodesku https://knowledge.autodesk.com/support/autocad-lt/learn-explore/caas/CloudHelp/cloudhelp/2019/ENU/AutoCAD-LT/files/GUID-90B274D0-C750-4ADA-9D3E-2C07B157F6A3-htm.html Większość nakładek ma jakieś swoje menu. Można podejrzeć jak to jest zrobione np. w Profilku naszego kolegi forumowego Gruzin albo w nakładkach e-cad. Każde takie menu siedzi w pliku *.mnu Zdaje się, że nowe wersje zwcada nie mają już tego pliku ale w wersji 2015+ taki plik jest w kartotece {user}\AppData\Roaming\ZWSOFT\ZWCAD\2015\en-US\Support Można go sobie pooglądać i zrobić coś a'la w podobie. -
Znalazłem. hatch.AppendLoop(HatchLoopTypes.External, collection); enum HatchLoopTypes można sumować logicznie hatch.AppendLoop(HatchLoopTypes.External | HatchLoopTypes.Outermost, collection);
-
Wygląda na to, że hund begraben jest w kodzie DXF 92. Po wstawieniu hatcha z .NET API kod wynosi 0. Sprawdziłem że dla kodu 1 jest liczona powierzchnia. Dla innych nie sprawdzałem. Wyciąg z dokumentacji kodów DXF Boundary Path Data The boundary of each hatch object is defined by a path (or loop) that consists of one or more segments. Path segment data varies depending on the entity type (or types) that make up the path. Each path segment is defined by its own set of group codes. For information about abbreviations and formatting used in this table, see Formatting Conventions in This Reference on page 2. Hatch boundary path data group codes Description Group code Boundary path type flag (bit coded): 92 0 = Default; 1 = External; 2 = Polyline 4 = Derived; 8 = Textbox; 16 = Outermost Lekarstwo w lisp'ie. (defun c:hatchfix ( / entity dxfdata old-dxf new-dxf dxfdata ) (setq entity (car (entsel)) dxfdata (entget entity) old-dxf (assoc 92 dxfdata) new-dxf '(92 . 1) dxfdata (subst new-dxf old-dxf dxfdata) ) (entmod dxfdata) ) W C# jeszcze nie znalazłem co i jak trzeba zafiksować żeby DXF 92 był 1.
-
[C#] zdarzenie przy komendzie CANNOSCALE
perlon odpowiedział(a) na perlon temat w Wsparcie programistyczne LISP i VisualLISP
Zgadza się. Ten Eventhandler jest bardziej precyzyjny. Dzięki. -
[C#] zdarzenie przy komendzie CANNOSCALE
perlon opublikował(a) temat w Wsparcie programistyczne LISP i VisualLISP
Witam Czy jest możliwe przechwycenie zdarzenia zmiany skali komendą _.CANNOSCALE? Testowałem Eventhandler CommandEnded ale on wysyła CommandEventArgs tylko z jednym polem : GlobalCommandName. Pole to zawiera jednak w tym przypadku jako nazwę komendy "SETVAR". Tak więc przechwytując zdarzenie CommandEnded co najwyżej dowiem się się, że była wykonana komenda SETVAR. A chciałbym wiedzieć czy była to komenda CANNOSCALE. Jak to zrobić? Może istnieje jakieś inne zdarzenie wywoływane przy okazji komendy CANNOSCALE? -
Palety narzędzi - tworzenie, edycja
perlon odpowiedział(a) na jacnightingale temat w ZWCAD Standard i Professional
Chodziło mi o _toolpalettes. Te XML'e są dla mnie pogmatwane i myślałem, że jest do tego jakiś pomocnik no i API, żeby to wczytać programowo bez angażowania użytkownika. Co do własnych palet to zdążyłem po informacji od Parikona doczytać i z grubsza uruchomić klasę PaletteSet. Jak się okazuje można tam wsadzić nie tylko WPF. WindowsForms doskonale w niej chodzi. Gdzieś widziałem nawet Javę. Wcześniej nie wiedziałem jak tego użyć a teraz mam nową zabawkę do zabawy -
Mógłbyś pokazać jak stworzyć własną paletę i jak wbiłeś kontrolkę WPF do takiej palety? Może jakiś link z materiałami do poczytania?
-
Palety narzędzi - tworzenie, edycja
perlon odpowiedział(a) na jacnightingale temat w ZWCAD Standard i Professional
Czy istnieje jakaś specyfikacja techniczna palety w ZwCAD'zie? Chodzi mi manual z opisem struktury pliku i ewentualnie jakiś user guide jak takie palety tworzyć. Czy istnieje jakieś API do tego aby w sposób programowy zaimportować własną paletę np z pozioomu ActivX lub .NET'a? -
[C#] Dostęp do tablicy symboli w klasie generycznej
perlon odpowiedział(a) na perlon temat w Wsparcie programistyczne LISP i VisualLISP
Tiaaaa.... proszę admina o wywalenie wątku w niebyt. Jeżeli nie to sam sobie odpowiem. Ślepota własna. Nie odblokowałem tablicy do zapisu. TTable symbolTable = (TTable)transaction.GetObject(GetObjectId(acDatabase, typeof(TTable)), mode: OpenMode.ForRead); // <- tylko do odczytu if (!symbolTable.Has(symbol.Name)) { symbolTable.UpgradeOpen(); // <- togo brakowało symbolTable.Add(symbol); transaction.AddNewlyCreatedDBObject(symbol, true); transaction.Commit(); } -
[C#] Dostęp do tablicy symboli w klasie generycznej
perlon opublikował(a) temat w Wsparcie programistyczne LISP i VisualLISP
Witam. Zderzyłem się z programistycznym problemem niekoniecznie związanym ściśle z ZwCAD'em ale wyszedł akurat przy programie na tą platformę. Prawdopodobnie jest to problem bardziej ogólny. Mam klasę generyczną która ma za zadanie sprawdzić czy w tablicy symboli istnieje przekazany symbol. Jeżeli nie to powinna ten symbol w tej tablicy utworzyć. public abstract class SymbolGenerator<TTable> : ISymbolGenerator where TTable : SymbolTable { public abstract void Generate(); public void Generate<TSymbol>(TSymbol symbol) where TSymbol : SymbolTableRecord { Document acDoc = Application.DocumentManager.MdiActiveDocument; Database acDatabase = acDoc.Database; using (Transaction transaction = acDoc.TransactionManager.StartTransaction()) { TTable symbolTable = (TTable)transaction.GetObject(GetObjectId(acDatabase, typeof(TTable)), mode: OpenMode.ForRead); if (!symbolTable.Has(symbol.Name)) { symbolTable.Add(symbol); // <- tu się wywala transaction.AddNewlyCreatedDBObject(symbol, true); transaction.Commit(); } } } private ObjectId GetObjectId(Database db, Type type) { switch(type.Name) { case "LayerTable": return db.LayerTableId; case "TextStyleTable": return db.TextStyleTableId; default: throw new NotSupportedException(); } } } Jak widać klasa powinna sobie poradzić z każdą tablicą symboli. Mnie w szczególności interesują LayerTable i TextStyleTable. Po przekazaniu innej ma rzucić wyjątek. Klasa jest abstrakcyjna więc potrzebuję klasy konkretnej. Przykładowa klasa do obsługi jakiegoś stylu tekstu. Klasa dziedziczy po SymbolGenerator<TextStyleTable> jak widać oczekuje typu TextStyleTable public class ElevationMarkTextStyleGenerator : SymbolGenerator<TextStyleTable>, IElevationMarkTextStyleGenerator { public override void Generate() { TextStyleTableRecord style = new TextStyleTableRecord(); style.Name = "ck_koty"; style.FileName = "simplex.shx"; style.XScale = 0.65; style.ObliquingAngle = 0; Generate(style); } } Wywołanie proste: var generator = new ElevationMarkTextStyleGenerator(); generator.Generate(); Application does not support just-in-time (JIT) debugging. See the end of this message for details. ************** Exception Text ************** System.Runtime.InteropServices.SEHException (0x80004005): External component has thrown an exception. at ZcDbSymbolTable.add(ZcDbSymbolTable* , ZcDbObjectId* , ZcDbSymbolTableRecord* ) at ZwSoft.ZwCAD.DatabaseServices.SymbolTable.Add(SymbolTableRecord value) at CADKitCore.Contract.SymbolGenerator`1.Generate[TSymbol](TSymbol symbol) in D:\dev\CSharp\Workspace\CADKit\CADKit\Contract\SymbolGenerator.cs:line 21 at CADKitElevationMarks.Model.ElevationMarkTextStyleGenerator.Generate() in D:\dev\CSharp\Workspace\CADKit\CADKitElevationMarks\Model\ElevationMarkTextStyleGenerator.cs:line 17 at CADKitElevationMarks.Contract.BaseElevationMark..ctor(IElevationMarkConfig _config) in D:\dev\CSharp\Workspace\CADKit\CADKitElevationMarks\Contract\BaseElevationMark.cs:line 44 at CADKitElevationMarks.Model.ArchtecturalElevationMarkPNB01025..ctor(IElevationMarkConfig config) in D:\dev\CSharp\Workspace\CADKit\CADKitElevationMarks\Model\ArchtecturalElevationMarkPNB01025.cs:line 16 at CADKitElevationMarks.Model.ElevationMarkFactoryPNB01025.GetElevationMark(ElevationMarkType type, IElevationMarkConfig config) in D:\dev\CSharp\Workspace\CADKit\CADKitElevationMarks\Model\ElevationMarkFactoryPNB01025.cs:line 15 at CADKitElevationMarks.Contract.ElevationMarkFactory.GetElevationMark(ElevationMarkType type) in D:\dev\CSharp\Workspace\CADKit\CADKitElevationMarks\Contract\ElevationMarkFactory.cs:line 15 at CADKitElevationMarks.Commands.ElevationMarkArch() in D:\dev\CSharp\Workspace\CADKit\CADKitElevationMarks\Commands.cs:line 17 at ZwSoft.ZwCAD.Runtime.CommandClass.InvokeHelper(MethodInfo mi, Object commandObject, Boolean bLispFunction) at ZwSoft.ZwCAD.Runtime.CommandClass.InvokeHelperWithExceptionFilter(MethodInfo mi, Object commandObject, Boolean bLispFunction) Prawdę mówiąc nie wiem co robię nie tak. Może znajdzie się ktoś bieglejszy, kto mi to wyjaśni? -
Nawiasy kwadratowe są potrzebne tylko w kolumnach które maja minus bo baza próbuje wykonać operację G minus marg. W klamerkach przyjmuje całość jako identyfikator. Jak widać poniżej w innych przypadkach nawiasy nie są potrzebne. Jak widzisz w kontrolkach musiałeś już użyć podkreślenia bo minus jest niedopuszczalny. Nazwy kolumn w bazach z polskimi literami nie wyglądają dobrze. Nagłówki w gridzie możesz ustawić osobno już z śćźł jak tam chcesz ale w bazie lepiej trzymać kolumny bez polskich liter. Masz wersję kwerendy która robi update w jednym kroku. U mnie bez nawiasów działa. public void ZmienDaneWTabeli() { this.db_con.Open(); SQLiteCommand db_cmd = db_con.CreateCommand(); db_cmd.CommandType = CommandType.Text; db_cmd.CommandText = "update " + nazwatabeli + " set " + "Format='" + UserControl2.nazwaformatki + "'," + "Wysokość='" + UserControl2.wysokosc + "'," + "Długość='" + UserControl2.dlugosc + "'," + "[G-marg]='" + UserControl2.G_marg + "'," + "[D-marg]='" + UserControl2.D_marg + "'," + "[L-marg]='" + UserControl2.L_marg + "'," + "[P-marg]='" + UserControl2.P_marg + "' " + "where Format='" + UserControl1.formatka + "'"; db_cmd.ExecuteNonQuery(); db_con.Close(); }
-
W uzupełnieniu: https://pl.wikipedia.org/wiki/SQL_injection https://www.plukasiewicz.net/Artykuly/SQLInjection_dla_poczatkujacych Ale dla tego typu zastosowań może nie warto za bardzo się ścierać. Moje propozycja : public bool CzyPowtorka(string nazwa) { this.db_con.Open(); SQLiteCommand db_cmd = db_con.CreateCommand(); db_cmd.CommandType = CommandType.Text; db_cmd.CommandText = "select count() from " + nazwatabeli + " where [Format] = '" + nazwa + "'"; var result = (long)db_cmd.ExecuteScalar(); db_con.Close(); return result > 0; } a dla pobierania danych z tabeli ramki_dane db_cmd.CommandText = "select * from " + nazwa_tabeli + " order by format desc"; Ponadto jeszcze jedna uwaga. DataTable dt = baza.PobierzDaneTabeli(baza.nazwatabeli); Skoro wywołujesz metodę PobierzDaneTabeli() klasy Base to instancja baza zna pole nazwatabeli. Nie ma sensu pobieranie z instancji jakiegoś pola po to żeby przekazać je z powrotem jako argument metody tej samej instancji. powinno być : DataTable dt = baza.PobierzDaneTabeli(); public DataTable PobierzDaneTabeli1() { var dt = new DataTable(); this.db_con.Open(); SQLiteCommand db_cmd = db_con.CreateCommand(); db_cmd.CommandType = CommandType.Text; db_cmd.CommandText = "select * from " + this.nazwatabeli + " order by format desc"; db_cmd.ExecuteNonQuery(); SQLiteDataAdapter da = new SQLiteDataAdapter(db_cmd); da.Fill(dt); this.db_con.Close(); return dt; } a nazwa tabeli skoro jest zmienną publiczną powinna być ustawiana w konstruktorze klasy. Są dwa konstruktory żeby działało po staremu w reszcie kodu. public Base(string _path) : this(_path, "ramki_dane") { } public Base(string _path, string _table) { this.nazwatabeli = _table; this.path = _path + "\\Bazy"; string sciezkaBaza = this.path + "\\pi.sqlite"; this.db_con = new SQLiteConnection($"Data Source = {sciezkaBaza}; Version = 3"); }
-
W bazach relacyjnych zakłada się, że kolejność rekordów jest taka jak kolejność dodawania. Odpowiednie sortowanie załatwia się klauzulą ORDER BY na etapie wyciągania danych z bazy a nie w momencie wstawiania. ORDER BY załatwia że zanim baza zwróci wynik zapytania to go najpierw posortuje. SELECT * FROM ramki_dane WHERE `jakis_filtr` ORDDER BY `Format` Oczywiście WHERE nie będzie jak chcesz wyciągnąć wszystkie rekordy. Żeby było bazie lżej zakłada się na kolumny indeksy. Są one aktualizowane przy każdym INSERT, DELETE i UPDATE. Indeksów może być wiele. Baza jest inteligentna i jeżeli uzna, że przy sortowaniu warto użyć jakiegoś indeksu to go użyje. Jeżeli nie znajdzie dobrego indeksu zastosuje ogólne metody sortowania. ORDER BY może zawierać łączenia pól np. ORDER BY `jakies_pole`+`inne_pole` Uwaga. Zapytania realizują również operacje matematyczne więc wartości liczbowe zostaną dodane i należy kontrolować typy. Może być np wymagana konwersja pola w samej kwerendzie. Ogólna uwaga ExecuteNonQuery() stosuje się do INSERT, UPDATE i DELETE. Do SELECT powinno się użyć ExecuteReader() dla zestawów i ExecuteScalar() gdy kwerenda zwraca dokładnie jedną daną. Taką kwerendą jest np SELECT COUNT() ... Zapuść sobie takie zapytanie w DB Browser SQLita to zobaczysz że danych z bazy można wyciągać mniej i osiągnąć ten sam rezultat. Generalnie wiele rzeczy da się zrobić po stronie bazy a w programie już tylko durne wyświetlanie gotowych zestawów posortowanych, pofiltrowanych, pogrupowanych i co tam jeszcze.
-
Warunek if(wierszy > 0) i for(int = 0; i < wiersz; i++ ) są tożsame. if jest niepotrzebny, bo jeżeli wierszy == 0 to 0 < 0 = false i pętla for się nie wykona ani razu. Na razie baza jest mikro i czas wykonania będzie nie mierzalny, ale co do zasady tego tak nie wolno robić !!! Co się stanie jak rekordów będzie 1000 000? To powinno się załatwić : SELECT COUNT() FROM ramki_dane WHERE format='jakis_format_z_pola_tekstowego' Jeżeli zwróci 0 to nie ma rekordu w przeciwnym razie wiadomo. Niech się baza męczy a nie twoja aplikacja. Generalnie SELECT * FROM ... bez WHERE to bardzo zła metoda. Zgadza się, ale lepiej żeby baza broniła się sama niż ma ją bronić zewnętrzna aplikacja. Wewnętrzne mechanizmy i algorytmy bazy będą zawsze lepsze niż iterowanie rekordów w aplikacji. Polecam indeks UNIQUE albo PRIMARY KEY
-
Myślałem o debugowniu z poziomu VS i wykonywaniu aplikacji w trybie krokowym. Znalezienie braku przypisania dt = baza.PobierzDaneTabeli(baza.nazwatabeli); // <- tu brakowało przypisania do dt bez debuggera zabrałoby mnóóóóóóóóstwo czasu. A można np tak: Dla aplikacji WPF mam niestety taki zonk : Aplikacje z Windows Forms nie mają z tym problemu. Może ktoś coś wie na ten temat?
-
Pierwsze uruchomienie pi_ramki przynajmniej u mnie pokazuje pustą bazę. Można to sprawdzić usuwając fizycznie plik bazy i odpalić ponownie ramki. Można to również prosto naprawić jak poniżej. DataTable dt = baza.PobierzDaneTabeli(baza.nazwatabeli); int wierszy = dt.Rows.Count; if (wierszy == 0) { baza.GetData(); dt = baza.PobierzDaneTabeli(baza.nazwatabeli); // <- tu brakowało przypisania do dt } dataGrid.ItemsSource = dt.DefaultView; Tak na marginesie GetData() powinno się raczej nazywać InsertData(). GetData raczej sugeruje że coś pobieramy z bazy a nie że do niej coś wkładamy. Druga rzecz. W kodzie używasz kolumny Format funkcjonalnie jako klucza głównego choć formalnie kolumna takim kluczem nie jest. Po nim robisz update. Wykonaj taki eksperyment: - do istniejącej bazy dodaj nowy rekord o nazwie która już istnieje np. A0 o jakiś dziwnych wymiarach np. 200x200. Nowy rekord zostanie dopisany i będą dwa A0 o różnych wymiarach. potem jednemu z nich zmień wymiar. Zobacz co stanie się z drugim. Jeżeli kolumna format jest kluczem głównym to należałoby założyć na nią indeks typu UNIQUE. CREATE UNIQUE INDEX `ID` ON `ramki_dane` ( `Format` ASC ); nazwa ID jest zwyczajową, może być dowolna inna. Kolejność sortowania wedle uznania. Po tej operacji dodanie drugiego formatu A0 nie będzie możliwe ale operacja zakończy się błędem. Przed wywołaniem baza.DodajDaneDoTabeli(); należy sprawdzić istnienie formatu jaki chcemy dodać. Można taką kontrolę podpiąć pod właściwość Enabled przycisku tak aby przycisk OK był nieaktywny jeżeli format już występuje. Oczywiście trzeba najpierw wiedzieć czy jest to tryb dopisywania czy aktualizacji. Alternatywnie i takie rozwiązanie wydaje się najsensowniejsze z punktu widzenia odpytywania bazy danych można zamiast powyższego dodać dodatkową kolumnę z autoincrementem jako klucz główny CREATE TABLE `ramki_dane` ( `ID` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `Format` Varchar ( 50 ), `Wysokość` INT, `Długość` INT, `G-marg` INT, `D-marg` INT, `L-marg` INT, `P-marg` INT ); Każde dodanie nowego rekordu spowoduje ustawienie pola ID o 1 większego niż ostatni istniejący w bazie. Trzeba jednak w takim wypadku zmodyfikować nieco kwerendę INSERT. Zamiast db_cmd.CommandText = "INSERT INTO " + nazwatabeli + " VALUES ('A4','210','297','25','5','5','5')"; powinno się w insercie wskazać nazwy kolumn db_cmd.CommandText = "INSERT INTO " + nazwatabeli + "('Format', 'Wysokość', 'Długość', 'G-marg', 'D-marg', 'L-marg', 'P-marg') VALUES ('A4','210','297','25','5','5','5')"; Nie zawsze insert musi zawierać komplet kolumn. Taki insert jest również poprawny. Brakującym polom zostaną nadane wartości domyślne jeżeli w bazie zostaną zadeklarowane. db_cmd.CommandText = "INSERT INTO " + nazwatabeli + "('Format', 'Wysokość', 'Długość') VALUES ('A4','210','297')"; Jeżeli w przyszłości powstanie pomysł zbudowania w bazie relacji miedzy dwoma różnymi tabelami to PRIMARY KEY stanie się niezbędny. Wszak SQLite jest relacyjną bazą danych więc jest więcej niż pewne że tak się kiedyś stanie. Nie wiem dlaczego nie mogę debugować kodu z WPF'em w dll'ce ładowanej do ZwCAD'a. Poradziłem sobie zakładając nowy projekt okienkowy WPF z oknem głównym aplikacji okienkowej i do niej wrzuciłem kontrolkę UserControl1. Uzyskałem zwykłą aplikację okienkową którą mogę debugować bez konieczności ładowania do środowiska ZwCAD. Może komuś się przyda jeżeli zechce debugować kody pisane w tym wątku. Z kosmetycznych rzeczy to warto dla bibliotek ZwCAD'a ustawić Copy Local na false, żeby się niepotrzebnie nie kopiowały do kartoteki bin. I tak mając zainstalowanego ZwCAD'a są dostępne globalnie. I jeszcze jedna uwaga kosmetyczna. Kod lepiej wygląda jak się stosuje jednolitą konwencję językową. DodajDaneDoTabeli() OK UpdateDaneWTabeli() już wygląda źle. Powinno być AktualizujDaneWTabeli(). AddBaseIfNotExist() też jest OK ale stosowanie równolegle polskiego i angielskiego nazewnictwa jest takie sobie. Polski język słabo się nadaje do jednoznacznego określania co dana metoda ma faktycznie robić albo jaka jest odpowiedzialność danej klasy. Takie rzeczy nazwa powinna wskazywać raczej precyzyjnie a polski język ma niestety w tym zakresie swoje mankamenty.
-
Jakoś mi się udało zrobić forka library1_zw na swoim githubie. Jest tam stworzona gałąź wersji z moim kodem. https://github.com/Perlon001/library1_zw/tree/ForkPerlon/library1_zw Myślałem że projekt byłby realizowany wspólnymi siłami, na zasadzie wspólnego zdobywania tzw. skill'a i trochę dla fanu, dając możliwość zwiększania funkcjonalności przy wspólnej pracy nad kodem. Można robić osobne nie powiązane moduły do zadań konkretnych. Każdy sobie i tylko udostępniać na licencji MIT w warunkach "takie jakie jest" i jak chcesz to sobie je weź. Tylko że jak wymyślę nową super zarypistą kotę do oznaczania rzędnych na rzutach to najłatwiej byłoby ją umieścić w moule od kot. Ale żeby ją mieć to muszę sobie nową dll'kę zmajstrować. Ja tak bardzo nie jestem przywiązany do swojego kodu żebym miał się bronić przed jego poprawianiem. Tym bardziej, że git pozwala na tworzenie wielu odgałęzień wersji i ich scalaniu wedle uznania. Muszę tylko się tylko nauczyć Wracając do sedna. Korzystając z zaproszenia do współpracy postanowiłem zmodyfikować nieco podejście do tematu rysowania kot. Na forum kilkukrotnie (pozdrawiam MartinS) była dyskusja na temat stosowania norm również w oznaczeniach na rysunków. Dlatego wymyśliłem sobie, że użytkownik bezie miał możliwość wyboru systemu rysowania (wyboru dostępnej normy) i za pomocą tej samej komendy rysować różne koty. Ta filozofia zapewne może mieć zastosowanie w wielu innych aspektach. Koty to tylko przykład jak za pomocą kiedyś wymyślonych przez mądrych ludzi wzorców realizować tego typu zadania. W tym konkretnym przypadku do tworzenia koty w odpowiednim standardzie wykorzystałem wzorzec fabryka. Duża część kodu do tworzenia koty nawet nie wie jaką kotę tworzy. Klasa abstrakcyjna BaseElevationMark dostarcza implementację wspólną dla wszystkich kot wysokościowych. Klasy konkretne w kilku linijkach załatwiają tylko te rzeczy którymi koty się różnią. Na to wszystko nałożona jest fabryka która zwraca na żądanie klasę konkretną ukrytą za interfejsem. Zdaję sobie sprawę, że mój kod ani nie jest odkrywczy ani nie jest super och i ach. Dlatego wszelkie uwagi są na prawdę mile widziane. Zapewne w kodzie są błędy, których ja jako autor nie jestem w stanie dostrzec. Jest również wiele rzeczy do poprawienia i uzupełnienia których mam świadomość. Feedbek bardzo mile widziany a za zrypkę też się nie obrażę. Mam również świadomość, że ilość linijek może nie być mniejsza niż w kodzie podstawowej biblioteki library1_zw (nie sprawdzałem). Szukałem sposobu na możliwość szybkiej rozbudowy o nowe standardy, a kod żeby spełniał zasady programowania obiektowego. Kończąc ten przydługawy elaborat chciałbym dodać, że spodziewałem się współpracy na poziomie tworzenia/pisania kodu w celach edukacyjno/hobbystycznych z efektem praktycznym, ale wygląda na to że zamysł Parikona jest nieco inny.
-
Popełniłem trochę kodu, głównie jako refaktoryzacja i uzyskanie podobnego efektu końcowego innymi metodami. Skupiłem się na części dot. kot wysokościowych. Chciałbym to wrzucić na githuba jako boczny branch ale coś mam chyba nie tak poustawiane, czegoś nie umiem albo repo jest zamknięte na obce commity . Jeszcze nie comittowałem do obcego repozytorium. Wklejanie całego kodu tutaj mija się z celem. Jak jakoś udostępnię cały kod to pozwolę sobie na kilka zdań objaśnienia co do mojego spojrzenia na to konkretne zagadnienie. Wszystko co udostępnię w ramach tego projektu będzie oczywiście na licencji MIT. Co do "zapętlenia" to rozwiązaniem chyba wystarczającym jest zamknięcie wywołania komendy w pętli nieskończonej + Exception. Klasę z komendami zrobiłem tak: [CommandMethod("KOTA_ARCH")] public void ArchElevationMark() { // co druga linijka z ponizszych jest niepotrzebna // konfiguracja z AppSettings IElevationMarkFactory markFactory1 = new ElevationMarkFactory(AppSettings.Instance.DrawingStandard).GetFactory(); // jak kto woli moze byc z łapy bez oglądania się na aktualne ustawienia IElevationMarkFactory markFactory2 = new ElevationMarkFactory(DrawingStandards.PN_B_01025).GetFactory(); // ustawienia defaultowe IElevationMark elevationMark1 = markFactory1.CreateElevationMark(ElevationMarkTypes.archMark); // albo wstrzykujemy konfiguracje. ElevationMarkConfig config = new ElevationMarkConfig(); config.ElevationMarkColor = Color.FromColorIndex(ColorMethod.ByAci, 5); config.ElevationMarkLayer = "OddzielnaWarstwaNaKoty"; IElevationMark elevationMark2 = markFactory1.CreateElevationMark(ElevationMarkTypes.archMark, config); try { while(true) { elevationMark1.Create(); } } catch (System.Exception ex) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message); } } [CommandMethod("KOTA_KONSTR")] public void ConstrElevationMark() { // tutaj wersja simply IElevationMarkFactory markFactory = new ElevationMarkFactory(AppSettings.Instance.DrawingStandard).GetFactory(); IElevationMark elevationMark = markFactory.CreateElevationMark(ElevationMarkTypes.constrMark); try { while(true) { elevationMark.Create(); } } catch (System.Exception ex) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message); } } Metoda w której wskazuję punkty wygląda tak: protected virtual void GetPoints() { Document acDoc = Application.DocumentManager.MdiActiveDocument; Application.SetSystemVariable("Osmode", 512); PromptPointOptions promptOptions = new PromptPointOptions("\nWskaż punkt wysokościowy: "); promptOptions.AllowNone = true; PromptPointResult pointResult = acDoc.Editor.GetPoint(promptOptions); if (pointResult.Status == PromptStatus.Cancel || pointResult.Status == PromptStatus.None) { throw new Exception("Cancel"); } elevationPoint = pointResult.Value; Application.SetSystemVariable("Osmode", 0); promptOptions.Message = "\nWskaż stronę : "; promptOptions.UseBasePoint = true; promptOptions.BasePoint = elevationPoint; pointResult = acDoc.Editor.GetPoint(promptOptions); if (pointResult.Status == PromptStatus.Cancel || pointResult.Status == PromptStatus.None) { throw new Exception("Cancel"); } side = GetSides(pointResult.Value); elevationPoint = new Point3d(Math.Round(elevationPoint.X, 3), Math.Round(elevationPoint.Y, 3), elevationPoint.Z); } Jak widać przy każdym oczekiwaniu na punkt jeżeli wciśnie się ESC lub ENTER pointResult otrzymuje status odpowiednio Cancel lub None. Wystarczy to sprawdzić i rzucić wyjątek który wywędruje aż do komendy startowej i tam dopiero zostanie obsłużony. Mój CommandMethod wygląda nieco dziwnie ale przy najbliższej okazji spróbuję wyjaśnić co się skąd wzięło. Następny ranek... Wygląda, że repozytorium https://github.com/Parikon/library1_zw jest zamknięte dla obcych commitów 😞