Visual C++ 2019 MFC karakterszélesség és Unicode-támogatás

Visual C++ 2019 MFC karakterszélesség és Unicode-támogatás
2021-03-22T22:32:54+01:00
2021-03-24T21:29:14+01:00
2022-10-15T21:25:55+02:00
x00
Visual C++ 2019 Community Edition, MFC-ben kezdenél készíteni egy IDE-t, Release AMD64. A Debug mód eleve nem megy, assertion miatt leáll, az MFC része a fájl, nem is említ általam készítettet. Release-ben próbáltam tehát. Több problémám van, a legfontosabb volt, hogy Consolas karakterek szélessége nem mindnek egyforma. Akár Visual Studio-ban, akár LibreOffice Writer-ben használom, 9-eset próbáltam 3-szoros nagyítással (a Windowsban 96 dpi * 3 = 288 dpi van beállítva). Csakhogy nekem ugyan a TextOut[W] kiírja rendesen, de ha a lekérdezem a karakterek szélességét, akkor már mindet 20 karakter szélesnek adja. A karakter 2 szélén lehet plusz térköz, ez az ABC szélessége a karakternek: A, C negatív is lehet. Próbáltam hogy ha negatív, akkor 0-nak veszem, ugyanis a B 1-32 között változik. Hát annál a pár széles karakternél maradt 20 a szélessége. Ez lenne a kisebb probléma. Egy IDE-nél minden karakternek más lehet a színe a szintaxiskiemelés miatt: megjegyzés, operátor, szám, szöveg, azonosító, foglalt szó, azonosító más színnel lehet a definíció helyén. Emiatt karakterenként kell kiírni. Csakhogy ami folytonos szövegben jól jelenik meg, az karakterenként kiírva már ismeretlen kódú karakter! Lásd a képet! Ide csak 1 fájlt tudok feltölteni, úgyhogy a kódot külön megjegyzésben töltöm fel. Köszönöm szépen aki segít.
Mutasd a teljes hozzászólást!
Csatolt állomány
char charwidth[0x10000]; const int lineheight = 60; // Sor magassága const int mincw = 20; // Alapértelemezett = leggyakoribb = minimális szélesség: szóköz, 0 kódú void CIDEView::OnDraw(CDC *pDC) { static bool MustGetWidth = true; if (MustGetWidth) { wchar_t a[2] = {0, 0}; CSize size; for (int j = 0; j < 0x10000; ++ j) { a[0] = (wchar_t) j; if (! GetTextExtentPoint32((HDC) *pDC, a, 2, &size)) { MessageBox(L"GetTextExtentPoint32 is failed"); AfxAbort(); } charwidth[j] = size.cx - 20; // A 0 kódú szélességét kell kivonni = szóköz szélessége } MustGetWidth = false; } const wchar_t text[] = L"∧∨∃∄∀∈∉∌∋∪⊂⊆⊄⊈⊃⊅⊇⊉⇒⇔≪≫∇⊥▲▼◆◇"; const wchar_t zero[] = L"0000000000000000000000000000"; pDC->TextOutW(4, 0, text); pDC->TextOutW(4, 2*lineheight, zero); for (int j = 0, pos = 4; text[j]; pos += charwidth[text[j]], ++j) pDC->DrawText(text+j, 1, CRect(pos, lineheight, 0, 0), DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX ); for (int j = 0, pos = 4; text[j]; pos += charwidth['0'], ++j) pDC->DrawText(zero, 1, CRect(pos, 3*lineheight, 0, 0), DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX ); }
DC kell hozzá, 3 másodperc Ryzen 3 3100-on, de legalább működik. Megnézem hogy a többi méretet esetleg a Windows-ban beállított 3-szoros nagyítás zavarta-e, mert az legalább gyors.
Mutasd a teljes hozzászólást!

  • A kód tehát (1 hozzászólásba csak 1 fájlt tudok csatolni, a képet már csatoltam).

    Előzőleg elírtam, 20 pixel szélesnek adja természetesen. Mind: CDC::GetCharWidth, CDC::GetOutputCharWidth, CDC::GetCharABCWidths is. Elvileg az utóbbi csak TrueType-on megy, a másik 2 csak nem TrueType-on, mégis megy mind a 3.

    A 80. sornál kezdődik, TextOutW-re rákeresve is oda áll.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Szerintem ez egy programhiba lesz, hiszen a szöveg hosszától függ hogy meg tudja-e jeleníteni helyesen. Próbáltam befrissíteni a legújabb 16.9.2-re, nem használt. a WinGDI elvileg már WinAPI-hívás lenne, úgyhogy lehet hogy mélyen van a hiba. Bejelentettem:

    TextOutW unicode support depends on the length of the text - Microsoft Q&A
    Mutasd a teljes hozzászólást!
  • Hibát úgy szoktak feltölteni, hogy csatolnak egy önálló minimális forrásfájlt (és az egyéb szükséges paramétereket, pl mely fordítóval, milyen flag-ekkel, stb..), mely produkálja a hibát.

    Én is ránéznék, ha lenne mire.. Így túl nagy erőfeszítés reprodukálni, főleg úgy, hogy írod, hogy debug módba el sem indul a programod (valószínűleg undefined behaviour, mert túl indexelsz, vagy kitudja). Ez még jobban eltántorít mindenkit, hogy rászánja a saját idejét, hogy megpróbálja reprodukálni..
    Mutasd a teljes hozzászólást!
  • Debug módban majd megnézem mi okozza: van egy ugyanilyen projektem, amit az MFC generált, abba beleteszem darabonként a saját kódomat, és megnézem mikor jelentkezik.

    Dialog-basednél is előjön, annál egyszerűbbek a generált fájlok, így azt töltöm fel, mivel project fájlok is vannak, .zip-ben. CunicodeDlg::OnPaint else ágban van a kiírás. Köszi hogy ránézel, szerintem a WinGDI-beli hiba.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Ha van mögötte egy 0 kódú karakter, akkor már jól írja ki! Ezt úgy lehet kiíratni, hogy nem CString, hanem wchar_t *, és megadjuk a hosszát is: jelen esetben 2, a kiírandó és a 0 kódú. Szóköz nem jó.

    pDC->SetTextAlign(TA_UPDATECP); pDC->MoveTo(4, 120); wchar_t tt[2] = {0, 0}; for (int i = 0; text; ++i) { tt[0] = text[i]; pDC->TextOutW(0, 0, tt, 2); CPoint const xy = pDC->GetCurrentPosition(); pDC->MoveTo(xy.x-20, xy.y); // 20 is the width of the character of code 0 }
    Mutasd a teljes hozzászólást!
  • Debug módban az assertion hibára nem jöttem rá. Csináltam egy másik ugyanolyan projektet, abban nem jelentkezik. Az összes assertet végigpróbáltam, most jöttem rá csak hogy lehet hogy több helyen jelentkezik a hiba: nem 1-esével kellett volna kikapcsolni, hanem az összeset kikapcsolni. CIDEDoc::OnNewDocument hívja az ősét, ennél jelez hibát, de a Step Into nem segít, csak az üzenettérképen meg az AssertValid metódusokon lépked. Próbáltam úgy is hogy előre odateszek egy töréspontot, így még a hibaüzenet előtt oda jutok, de ugyanúgy nem derült ki mi a hiba. Csatolom a .zip fájlt. Próbáltam parancssorba: IDE /Unregister, de nem segített.
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Sajnos csak gcc-m és clang-om van, így nem tudom most tesztelni ( nem fogok VS-t telepíteni :( )

    (MFC-vel nem csak operációs rendszerhez kötöd magad, hanem fordítóhoz is..)
    Mutasd a teljes hozzászólást!
  • Már megvan. Az erőforrás-szerkesztőben a sztringtáblában kiterjesztésnek nem dt kell hanem .dt: a . lemaradt. Imádom amikor ilyen pontosan megmondja mi is a hiba: sehogy. Most inkább az érdekelne, hogy a TextOutW helyett van-e valami olyan megoldás, hogy ha egy karaktert át akarunk írni, ne kelljen miatta az egész sort végigírni. Ugyanis a jelenlegi megoldásban a mögötteálló karaktert is letörli. A globális, <WinGDI.h>-beli TextOutW is ilyen sajnos.

    Illetve a karakterszélesség-lekérdezés is jó lenne. 15 másodperc mire kiírja a 65536 karaktert, hogy lekérdezzem a kiírása utáni kurzorpozíciót. Megpróbálom memóriában levő bitmapbe, akár 2 vagy 256 színűbe, illetve fájlba is menthetem: 64 KB mindössze.
    Mutasd a teljes hozzászólást!
  • Ilyen, és ehhez hasonló problémákról és nyűgökről írtak a többiek, és én is az általad korábban indított MFC-s témakörben. Ezért nem hatékony eszköz az MFC alkalmazása manapság, mert ezek a problémák csak az időt, és az energiát viszik, a szoftvered fejlesztésével meg nem tudsz haladni.
    Mutasd a teljes hozzászólást!
  • Másnál jó? Na mert a WinGDI tudtommal nem az MFC része, és a Windowsban én nem találtam mégelemibb szövegkiírót. Pedig olyat kerestem volna. Ott a szöveg, ki lehet próbálni hogy a világlegjobbja WPF, WinForms-ban, C#-ban működik-e. Szerintem nem.

    ∧∨∃∄∀∈∉∌∋∪⊂⊆⊄⊈⊃⊅⊇⊉⇒⇔≪≫∇⊥▲▼◆◇

    28 karakter. Szélesebbnek kell lennie mint a szóköz (Consolas font), és 1-esével karakterenként kiírva is mennie kell, hiszen ha 1 sorban csak 1 karakter van, akkor is így kell kinézzen, nem dobozban kérdőjel. A szélessége lekérdezésekor is szélesebbnek kell lennie: amikor kiírás nélkül lekérdezzük. Az egérrel kattintáskor ugyanis az egérpozícióból meg kell tudni határozni a karakterpozíciót.
    Mutasd a teljes hozzászólást!
  • char charwidth[0x10000]; wchar_t a[2] = {0, 0}; CSize size; for (int i = 0; i < 0x10000; ++ i) { a[0] = (wchar_t) i; if (! GetTextExtentPoint32((HDC) *pDC, a, 1, &size)) { MessageBox(L"GetTextExtentPoint32 failed"); AfxAbort(); } charwidth[i] = size.cx; }
    Ehhez DC kell, de legalább megy, 3 másodperc Ryzen 3 3100-on. Viszont a karakterek kiírása még nincs meg úgy hogy a mögötteállót ne törölje le. Lehet beállítani hogy a háttérszínt ne rajzolja ki, de ekkor az aktuálisat kell előbb letörölni, így 2-szeres idő.
    Mutasd a teljes hozzászólást!
  • char charwidth[0x10000]; const int lineheight = 60; // Sor magassága const int mincw = 20; // Alapértelemezett = leggyakoribb = minimális szélesség: szóköz, 0 kódú void CIDEView::OnDraw(CDC *pDC) { static bool MustGetWidth = true; if (MustGetWidth) { wchar_t a[2] = {0, 0}; CSize size; for (int j = 0; j < 0x10000; ++ j) { a[0] = (wchar_t) j; if (! GetTextExtentPoint32((HDC) *pDC, a, 2, &size)) { MessageBox(L"GetTextExtentPoint32 is failed"); AfxAbort(); } charwidth[j] = size.cx - 20; // A 0 kódú szélességét kell kivonni = szóköz szélessége } MustGetWidth = false; } const wchar_t text[] = L"∧∨∃∄∀∈∉∌∋∪⊂⊆⊄⊈⊃⊅⊇⊉⇒⇔≪≫∇⊥▲▼◆◇"; const wchar_t zero[] = L"0000000000000000000000000000"; pDC->TextOutW(4, 0, text); pDC->TextOutW(4, 2*lineheight, zero); for (int j = 0, pos = 4; text[j]; pos += charwidth[text[j]], ++j) pDC->DrawText(text+j, 1, CRect(pos, lineheight, 0, 0), DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX ); for (int j = 0, pos = 4; text[j]; pos += charwidth['0'], ++j) pDC->DrawText(zero, 1, CRect(pos, 3*lineheight, 0, 0), DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX ); }
    DC kell hozzá, 3 másodperc Ryzen 3 3100-on, de legalább működik. Megnézem hogy a többi méretet esetleg a Windows-ban beállított 3-szoros nagyítás zavarta-e, mert az legalább gyors.
    Mutasd a teljes hozzászólást!
  • Miért kéred le az összes létező karakter hosszát? Neked csak arra a 28-ra lenne szükséged, nem?
    Mutasd a teljes hozzászólást!
  • Ez ugye egy IDE, ami egy szövegszerkesztő. Egyszerűbb lekérdezni eleve. Amikor egérrel kattintok, akkor a koordinátából karakterbeli hely kell, ahhoz kell. Így eleve adott lesz.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd