Ahoj, nevíte jestli je novější GDI, nebo GDI+ a jaká třída (TextRenderer, Graphics) patří k čemu? Když se kouknu na wiki, tak je novější GDI+ (třída Graphics), což je logické i podle názvu. Tedy https://docs.microsoft.com/cs-cz/dotnet/api/system.windows.forms.label.usecompatibletextrendering?view=windowsdesktop-6.0 mi přijde zase naopak. Tak jestli mi to může někdo osvětlit.
Fórum › .NET
Grafika GDI vs GDI+
máš to nějaký celý popletený ............ tady to máš napsaný
https://cs.wikipedia.org/wiki/Graphics_Device_Interface
novější je GDI+ z 90. let minulýho století ... ale pochybuju že bys v tom chtěl dělat .. to se hodí na malý věci a práci s C/C++
pokud chceš 3D grafiku máš v dnešní době na výběr ze starých knihoven C++/OpenGL a C++/DirectX a novější a multiplatformní C++/Vulkan. Ve spojení s C++ fungují všechny. je to ale hodně náročný. Tady máš o GDI+ knížku
https://www.databazeknih.cz/knihy/programovani-v-gdi-v-prikladech-173442
Z novějších knihoven je tu pak C#/Unity nebo právě C++/Vulkan a mužeš použít i C++/Qt což je spíš na 2D. Obzvláště C++/Qt se hodně používá v průmyslu např. na vývoj 2D grafiky např. pro palubní desky aut atd.
Nechápu pojem třída ??? To si zase s něčim pleteš
http://kmlinux.fjfi.cvut.cz/~fabiadav/cecko/poznamky-k-jazyku-c_plus_plus/tridy
Jinak mám pocit že si pleteš profi knihovny na práci s 3D grafikou neboli OpenGL, DirectX, Vulkan ve kterých se dělaj hry jako je CallOfDuty a knihovny pro vytváření GUI v systému .NET pro desktopové aplikace jako je např. právě účetnictví. Stará knihovna .NET 1.xx-4.8 WinForms z roku 2001 (nástupce knihovny MFC) používala pomalé funkce GDI/GDI+. Existuje aktualizovaná verze knihovny Winforms a to knihovna C# .NET 6/7 WinForms. Novější C# .NET WPF z roku 2006 používal už DirectX a nejnovější WinUI je multiplatformní a ještě není hotová. Momentálně je stará WPF předělaná a jmenuje se .NET 6/7 WPF. Pokud chceš dělat 3D grafiku takže HRY tak musíš používat C#/Unity, C++/OpenGL (OpenTK), C++/DirectX, C++/Vulkan a další... třeba starší C#/SlimDX, C#/SharpDX, C#/XNA atd... Pokud ti stačí rychlá 2D grafika při vytváření GUI pro programy jako je třeba účetnictví tak potřebuješ C# .NET 6/7 WPF nebo novější C# WinUI (až bude hotová tak za rok dva). Existuje ještě nejstarší knihovna C++/MFC z 90. let a ta používá jen GDI/GDI+. Tady v čr se v ní už skoro nedělá. Používaj ji firmy hlavně v Německu, Francii, USA atd. Ty by si měl pro vytváření jednoduchých aplikaci s 2D GUI používat asi nejspíš C# .NET core 6 WPF. Tady sou manuály: https://www.wpftutorial.net/…; https://wpf-tutorial.com/
WPF je sice složitější než WinForms ale má mnoho možností a hlavně můžeš najít pracovní uplatnění jako programátor v C# WPF.
#5 gna
Takže tím je to divný, nejprve používali novější GDI+ a pak kvůli kompatibilitě přešli na GDI?
Další divné věci jsem četl ohledně důvodu vývoje GDI+, kde píšou kvůli rychlosti, ale co jsem viděl testy tak je GDI rychlejší, ale zase GDI+ vypadá lépe, protože používá různé efekty (další důvod je, že není hardwarově akcelerované).
#3 JerryM
Žádnou komplikovanou grafiku nepotřebuju, vlastně zatím hlavně něco co dobře spočte délku textu. Tedy jestli pomocí TextRenderer.MeasureText, nebo třída Graphics instance.MeasureString. Ale ani jedno neodpovídá měření, nejspíš proto, že obojí připočítává i nějaké pixely před a za textem. Nevíte někdo jaký algoritmus to používá?
máš neobvyklé požadavky
nejdříve bylo GDI a pak GDI+ .. a ANO obojí je pomalé ... proto se to už dnes nepoužívá
rozměry textu se měří podle standardů definovaných Microsoftem
https://stackoverflow.com/questions/20177781/how-to-get-text-width-directx-c
v knihovně DirectX a nic jiného bych už dnes asi nepoužíval ...
https://books.google.cz/books?id=j2N4jrL7jFkC&pg=PA210&lpg=PA210&dq=DirectX+text+length+measurement&source=bl&ots=W-G0fTRbDd&sig=ACfU3U08cYbHPxDlviVfgh2S1vGnpsYTDw&hl=cs&sa=X&ved=2ahUKEwiY64WL_4P3AhVwwQIHHemfAGkQ6AF6BAgREAM#v=onepage&q=DirectX%20text%20length%20measurement&f=false
https://stackoverflow.com/questions/5708860/how-do-you-draw-text-in-directx-11
http://www.rastertek.com/dx11tut12.html
#9 JerryM
Neobvyklé úplně ne, respektive na netu je dost diskuzí kde se to řeší, ale nic co bych považoval za dokonalé.
Tu rychlost jsem psal jako údajný důvod vývoje GDI+, jinak mě netrápí. UI mam v GDI, nebo GDI+, tak to prostě musim použít. Také nevim jestli jste někdo řešil třeba "zalamování" textu a počítání výšky řádku sloučené buňky v Excelu. Aspoň v mojí verzi Excelu jsem na to nic rozumného, tedy přímo pomoci API nenašel a opět co jde ohledně toho najít na netu se točí kolem těchto tříd.
Našel jsem něco co není ideální, ale aspoň nějak to ve starém dobrém System.Windows.Forms funguje.
int sirkaPodtrzitek = TextRenderer.MeasureText("__", label.Font).Width;
int sirkaSpatne = TextRenderer.MeasureText( label.Text , label.Font).Width;
int sirkaPresne = TextRenderer.MeasureText("_" + label.Text + "_", label.Font).Width - sirkaPodtrzitek;
#7 Honza
Takže tím je to divný, nejprve používali novější GDI+ a pak kvůli kompatibilitě přešli na GDI?
GDI+ není novější v tom smyslu, že by nahrazovalo staré GDI (i když má nové fíčury), ale prostě existují paralelně. I když původní plán nejspíš byl, že všechno pěkně vymazlí a bude to paráda. Na GDI pak přešli kvůli výkonu, je to hnusný, ale rychlý :) Kompatibilita v názvu té property znamená jen to, že si můžeš zapnout vykreslování postaru.
už nepoužívej starou .NET WinForms a přejdi radši na novou .NET core 6 WPF.
https://stackoverflow.com/questions/1296951/usecompatibletextrendering-property-not-created-by-designer-when-it-is-set-to-fa
https://docs.microsoft.com/cs-cz/dotnet/api/system.windows.forms.label.usecompatibletextrendering?view=windowsdesktop-6.0
#14 JerryM
1) Já bych rád ale to není na mě, zatím jsem neprotlačil ani aby se do databázi nezapisovala čísla ID jako string (navrch unicode).
2) Při servisování existujících kódů spočívající v odstranění chybky, malém vylepšení atd. to nemá cenu celé přepisovat.
Já aspoň myslím, že potřebuju měřit text, abych docílil toho, že např. controlu DataGridView následně podle toho nastavim šířku. Normálně to funguje opačně, je nějak nastavena šířka a vnitřní logikou se obsah vykreslí. Třeba to i samo dokáže nastavovat jednotlivé šířky sloupců podle obsahu (podle nejširšího textu ve sloupci), ale jen do limitu daného celkovou velikostí controlu. Mým způsobem bych šířku sloupců spočetl sám, podle toho nastavit celkovou šířku controlu a na pevno nastavit i jednotlivé šířky sloupců. Následně podle velikosti controlu nastavit velikost okna formuláře. Zjednodušeně se ve výsledku vykreslí okno, ve kterém je vidět celý obsah všech sloupců.
Windows mají možnost volby mezi výkonem a vzhledem, možná to taky souvisí s tím jaký renderer se používá, ale nic jsem k tomu nenašel. Jen, že systém má k dispozici GDI, GDI+ a DirectX.
U WinForms DataGridView se samozřejmě dá nastavit aby se jednotlivé buňky rozměrově nastavovaly samy automatickypodle vkládaného textu to je pravda, ale nezapomeň, že v době načítání musí být tato vlastnost vypnutá protože to prodlužuje dobu načítání dat do DataGridView. Zapíná se to až při Refresh().
Jinak šířku textu zjistíš pomocí WinAPI funkcí
https://docs.microsoft.com/en-us/windows/win32/gdi/font-and-text-functions
https://stackoverflow.com/questions/548200/getting-the-font-size-of-a-menu-item-in-the-win32-api
https://stackoverflow.com/questions/4992121/get-default-font-height-for-win32-drawtext
Ano, tak jak už sme tu řekli GDI/GDI+ je nejpomalejší a DirectX nejrychlejší .. má to ale háček staré .NET WinForms používají GDI/GDI+ .. takže máš smulu ...
#18 Honza
jinak na výpočet šířky a výšky textu se dá na internetu najít spousta příkladů
https://www.tek-tips.com/viewthread.cfm?qid=1028775
takže pokud by si chtěl být "DOKONALY" tak si napíšeš knihovnu v C++ a pak k tomu wrapper v C++/CLI do řízeného kodu a pak to použiješ v C# a ta knihovna ti bude zjišťovat parametry textu ...
#18 Honza
TextRenderer.MeasureText by ti na toto měl stačit, vrací to (myslím že vždy) o trošku větší rozměr chlívečku než je vykreslovaný text. Což je myslím pro tvůj účel vhodné.
(zajímal by mě obsah textu v labelu u příkladu int sirkaSpatne = TextRenderer.MeasureText( label.Text...)
Pokud ti to vrací u některého textu menší velikost můžeš taky zkusit MeasureCharacterRanges, to má víc možností nastavení.
#21 JerryM
Potřebuju to teď nějak rychle "odfláknout", jestli to poběží pomalu nevadí. Hlavně napsat co nejméně kódu a spíš použít něco hotového. Zatím zkusím nepoužívat hned celý DataGridView, ale jen jeho sloupec, který za mě max. šířku spočte a podle jednotlivých sloupců nastavit rozměr DataGridView a padla :)
Napadá mě ale jestli jste někdo neviděl, nebo si nedokážete představit tabulku, která rozděluju šířku mezi sloupce podle aktuálně viditelného obsahu? Při scrolování by se tedy šířky sloupců měnily podle toho co je zrovna ve viditelné oblasti, celkové okno by mělo pevný rozměr. Byl by to moc velký chaos? Jsem něco takového asi nikde neviděl.
Pokud vim tak šířka sloupce podle aktuálního obsahu se pro DataGridView ve starý knihovně .NET Winforms normálně nastavuje nějakým parametrem ... na to nepotřebuješ nic počítat
DataGridView.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders;
https://docs.microsoft.com/cs-cz/dotnet/api/system.windows.forms.datagridview.autosizecolumnsmode?view=windowsdesktop-6.0
DataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
#22 BDS
label.Text = "AAAAA";
Spíš jsem to chtěl nějak zkontrolovat, což se dělá blbě, když to vrací jiný rozměr než má viditelná oblast textu. Vždy to bylo větší, protože to na začátek a konec vkládá nějakou mezeru.
Na to co chci teď je to asi jedno, ale pokud je potřeba třeba text v nějakém místě zalomit (na konci řádku), tak mi přijde lepší rozložit text na slova a postupně připočítávat slova a ' ' bez těch mezer navíc. Než testovat stále delší část stringu včetně mezer.
když nastavuješ properties pro celej DataGridView tak využiješ tohle:
this.dataGridView4.Rows.Clear();
this.dataGridView4.Columns.Clear();
this.dataGridView4.Refresh();
this.dataGridView4.SuspendLayout();
this.dataGridView4.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
this.dataGridView4.ColumnHeadersVisible = true;
this.dataGridView4.RowHeadersVisible = true;
this.dataGridView4.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.dataGridView4.AllowUserToAddRows = false;
this.dataGridView4.AllowUserToResizeColumns = false;
this.dataGridView4.AllowUserToResizeRows = false;
this.dataGridView4.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this.dataGridView4.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.SingleHorizontal;
this.dataGridView4.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing; //.AutoSize;
this.dataGridView4.MultiSelect = true;
this.dataGridView4.AutoGenerateColumns = false;
a pak pro jednotlivý sloupce:
// add first column
col = new System.Windows.Forms.DataGridViewTextBoxColumn();
col.HeaderText = "No.";
col.Width = 50;
col.DefaultCellStyle.Font = new System.Drawing.Font("Courier New", 8);
col.DefaultCellStyle.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
col.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; //.AllCells; //::::None;
this.dataGridView4.Columns.Add(col);
a teprve až když máš celou datagridview sestavenou tak dáš:
for (Int32 i = 0; i < this.dataGridView4.Columns.Count; i++)
{
this.dataGridView4.Columns[i].AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
}// for
this.dataGridView4.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView4.Refresh();
this.dataGridView4.ResumeLayout();
this.dataGridView4.PerformLayout();
this.dataGridView4.Rows[0].Selected = true;
chápěš jo ?
label.Text = "AAAAA"; samozřejmě při dotazu na velikost vrací rozměr včetně Margin takže pak ti to logicky nemuže vyjít .. záleží na tom na co se ptáš ... začínáš mě připadat jako důchodce co se nudí ... ty tvoje dotazy sou fakt uchylný .. hlavně neřikej že tohle máš do práce jako programátor
#24 JerryM
Jsem psal, že to za mě ten sloupec spočte sám, ale lepší je metoda GetPreferredWidth. Měl jsem to nastavené jak píšeš, ale tam to funguje jen pokud se sloupce do DataGridViewu vejdou a nevěděl jsem jak nezávisle na tom jak je šířka DataGridViewu zrovna nastavena (stačila pro všechny sloupce, nebo ne) zjistit potřebnou šířku, která se nemusí shodovat s nastavenou a naopak až podle těch šířek nastavit DataGridView.
Jinak ono to má tu možnost přizpůsobovat šířku aktuálně zobrazeným buňkám, to musim vyzkoušet jak to vypadá.
for (Int32 i = 0; i < this.dataGridView4.Columns.Count; i++)
{
this.dataGridView4.Columns[i].AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
}// for
this.dataGridView4.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView4.Refresh();
jinak pořád nechápeme co má společnýho Label.Text s DataGridView (DGV) ???
do DGV se přeci muže vložit obyčejně nějakej String jen obyčejným přiřazením, vkládat Objekt Label a teprve až pak do Label.Text nějakej String je přeci blbost ...
Tak téma začalo dotazem GDI vs GDI+, což jsem konečně pochopil jak to je. Přesné měření textu záleží na rendereru, což je souvislost s GDI/GDI+. DataGridView byla podotázka na konkrétní použití, stejně jako Label používají v rámci Window Forms stejný renderer. Třeba to použiju na něco komplikovanějšího, kde si overloadnu vykreslovaní nějakého controlu, nebo části. Proč to musíš řešit na co to kdo použije, nebo jestli vůbec, tak min. je dobré aspoň trochu vědět jak to interně funguje.
Možná ještě takhle: počáteční záhada byla, proč funkce z obou typů rendererů vrací jiný počet pixelů šířky než kolik jinak opravdu má ten Label s textem "AAAAA". Teď už vim, že za to můžou mezery před a za textem, než že by bylo něco špatného na použité funkci.
žádná anonymní "mezera" :) okolo začátečních a koncových písmen neni ani pro rastrový ani pro vektorový písma ... tomu se řiká margin a padding properties v systému .NET ... koukni se na WinAPI wingdi.h a na jednotlivé funkce a strukturu TEXTMETRICA a TEXTMETRICW ...
#40 JerryM
To řešení, kdy se pomocí podtržítek ty mezery odfiltrují bylo někde (nejspíš na stackoverflow) nejlépe hodnocené řešení, ale možná máš lepší. Problém je, že té funkci na měření předáváš jen string a font, tam nikde margin/padding nevidim. Měl by tedy vyjít rozměr viditelných pixelů stejný jako je text zobrazený třeba pomocí Labelu? Neměřím prostor pro text v controlu, ale měřím jen od prvního viditelného pixelu textu do posledního, což vyjde dobře pokud se odstraní ta anonymní mezera. O samotný control nejde, to je jen něco co mi text vykreslí, abych ho mohl kontrolně oměřit, je jedno jaké hodnoty má margin/padding, to text jen nějakým směrem posune, ale viditelná oblast pixelů textů je stále stejná.
před mnoha lety jsem tohle potřeboval pro objekt ComboBox, ale už si to nepamatuju, zkusim to najít, každopádně se to co chceš musí počítat z nadřazeného objektu nikoliv podle objektu co je vevnitř text podle textu ... v tom je ten fígl
Když se podíváš do střev Frameworku, tak interně System.Windows.Forms používá toto:
internal override Size GetPreferredSizeCore(Size proposedConstraints) {
if(FlatStyle != FlatStyle.System) {
Size prefSize = base.GetPreferredSizeCore(proposedConstraints);
return AutoSizeMode == AutoSizeMode.GrowAndShrink ? prefSize : LayoutUtils.UnionSizes(prefSize, Size);
}
if (systemSize.Width == InvalidDimensionValue) {
Size requiredSize;
// Note: The result from the BCM_GETIDEALSIZE message isn't accurate if the font has been
// changed, because this method is called before the font is set into the device context.
// Commenting this line is the fix for bug VSWhidbey#228843.
//if(UnsafeNativeMethods.SendMessage(hWnd, NativeMethods.BCM_GETIDEALSIZE, 0, size) != IntPtr.Zero) {
// requiredSize = size.ToSize(); ...
requiredSize = TextRenderer.MeasureText(this.Text, this.Font);
requiredSize = SizeFromClientSize(requiredSize);
// This padding makes FlatStyle.System about the same size as FlatStyle.Standard
// with an 8px font.
requiredSize.Width += 14;
requiredSize.Height += 9;
systemSize = requiredSize;
}
Size paddedSize = systemSize + Padding.Size;
return AutoSizeMode == AutoSizeMode.GrowAndShrink ? paddedSize : LayoutUtils.UnionSizes(paddedSize, Size);
}
Ale tak jako vždy je ten kód téměř nekonečný chain metod, které dřív nebo později stejně volají nějaké dll, takže vytahnout z toho něco je peklo.
Dál jsem našel v třídě WindowsGraphics
//
// DrawText returns a rectangle useful for aligning, but not guaranteed to encompass all
// pixels (its not a FitBlackBox, if the text is italicized, it will overhang on the right.)
// So we need to account for this.
//
IntNativeMethods.DRAWTEXTPARAMS dtparams = null;
#if OPTIMIZED_MEASUREMENTDC
// use the cache if we've got it
if (MeasurementDCInfo.IsMeasurementDC(this.DeviceContext))
{
dtparams = MeasurementDCInfo.GetTextMargins(this,font);
}
#endif
if (dtparams == null)
{
dtparams = GetTextMargins(font);
}
//
// If Width / Height are < 0, we need to make them larger or DrawText will return
// an unbounded measurement when we actually trying to make it very narrow.
//
int minWidth = 1 + dtparams.iLeftMargin + dtparams.iRightMargin;
if( proposedSize.Width <= minWidth ) {
proposedSize.Width = minWidth;
}
if( proposedSize.Height <= 0 ) {
proposedSize.Height = 1;
Takže si to z fontu nějaký interní margin dopočte.
tady sem něco napsal
https://uloz.to/file/bGRKqP0VNNa9/app10-net4-textwidth-zip#!ZGuyMGR1BGR0ZJSuAGIxBGxjLzZ4BJSBGyI2pKMdoIIiBQEu
máš tam nastavenou automatickou volbu šířky sloupce podle vkládaného textu a navíc zjištění rozměrů textu příkazem MeasureString ...
jenom aby si to správně pochopil, tak kdyby si chtěl skutečně dodržet "přesně" rozměry v pixelech tak bys musel vyrendrovat text do bitmapy a tu pak zapsat do buňky DGV - to tam taky máš zapsaný jako kod, ale nechápu k čemu ti to bude .. protože rastrovej font je poněkud jinej nežli TrueType ... chápeš jo
Díky, večer se na to kouknu. Myslel jsem něco jako https://stackoverflow.com/questions/4080719/placing-images-and-strings-with-a-c-sharp-combobox , kde si obrázek a text umístí podle potřeby. Zrovna toto je příklad, něčeho co jinak nejde, nebo nevim jak. U DataGridViewu nejdou třeba sdílené buňky a následně umístit text svisle na střed lichého počtu řádků (mimo řádek DGV). Mně by se hodil jednoduchý výpis textu, ale ve stylu tabulky (nejlépe DGV vůbec nepoužít, ale třeba jen textbox), ale v textboxu nejde text, natož několik textů umisťovat tak, aby vše ve sloupci začínalo na stejném pixelu. S vlastním vykreslením by to snad šlo, ale na to je právě potřeba znát přesné rozměry textu.
ten příklad samozřejmě UMÍ zakreslit text do buňky kam chceš ... máš tam přeci volitelnou pozici ne ? zbytek záleží na způsobu zarovnání.
no tak jinak můžeš použít TableLayoutPanel... chápeš jo ?
https://stackoverflow.com/questions/9390641/how-to-merge-two-cells-in-table-layout
hele ... ty jinak pracuješ jako noční hlídač ? nebo jako sekretářka ? a programování máš jako koníčka ? nebo pracuješ jako ??? bezdomovec ?
hele a víš o tom, že odpověď na tvoji původní otázku je tady ?
https://docs.microsoft.com/cs-cz/dotnet/api/system.windows.forms.label.usecompatibletextrendering?view=windowsdesktop-6.0
to je ten odkaz co si v otázce posílal .... chápeš jo ? je to tam napsaný v posledním odstavci ... rozdíl mezi .NET 1.0 a .NET 1.1... ale obě verze knihovny už jsou nepodporovaný tak je to jedno ... takže používáš evidentně .NET 4.7.2/4.8 a GDI+ nikoliv starou GDI, která ještě "ujíždí" na VideoBiosu.
Přidej příspěvek
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku
×Vložení zdrojáku
×Vložení obrázku
×Vložení videa
Uživatelé prohlížející si toto vlákno
Podobná vlákna
GDI, GDI+, nebo DirectX — založil Kvarköny
GDI objects — založil LJ1024
Tisk pomocí Windows GDI — založil Jan Netopil
C++ grafika — založil Hornster
Grafika — založil Michal115
Moderátoři diskuze