Lekce 3 - Tisk formuláře a ovládacích prvků Windows Forms
V minulém díle jsme končili s trochu teorie a použitých názvů. Připravíme si naši knihovnu C++/CLR:safe pro pokračování. V tabulce je ukázka vlivu přepínače C++/CLR na možnosti programátora. Zde nebudu vysvětlovat jednotlivé možnosti, jsou dostatečně popsané na webu.

Příprava (dll) knihovny Class2
Ve VS otevřeme průzkumník řešení a myší najedeme na MyClass2. Pravé tlačítko myši otevřeme vlastnosti. Tlačítkem Add.New Reference... přidáme Microsoft.VisualBasic.Power.Packs.Stejně přidáme i System.Windows.Forms a přidáme System.Drawing, viz obrázek.

Znovu přejdeme na Stránky vlastností MyClass2 a přejdeme na Vlastnosti
Konfigurace a v poli
Common Language Runtime Support naklikneme: Safe MSIL Common Language
Runtime Support (/clr:safe). Stránky vlastností MyClass2 musí být
nastaveny v Konfiguraci na Všechny konfigurace.
Funkce FnSetGraphics(Graphics^ gr) a FnRealPageSettingsBounds(Rectangle
RealPageSetting) jsou statické. To znamená, že je pouze jedna instance této
funkce bez ohledu kolikrát je třída použita.
Znovu přikládám obrázek.

V průzkumníku řešení vidíme, že máme Header Files - MyClass2.h a
Source Files - MyClass2.cpp.
Zde doporučuji psát kód programu do obou, není to sice nutné, při
větším projektu ztratíte přehled a váš program bude špatně čitelný.
Do Header souboru zapisujeme pouze hlavičky funkcí.
Programujeme v knihovně MyClass2
Přejdeme do knihovny MyClass1 na funkci PdPrintPage(....), zrušíme komentář u FnSetGraphics(graphics), zkopírujeme tuto funkci do schránky, otevřeme MyClass2 a vložíme do Class2.
Upravíme hlavičkový soubor:
#pragma once //hlavička může být načtena pouze 1x velmi důležité namespace FormPrintDemo { public ref class Class2 //v C# -> public class Class2 { public: Class2(); //konstruktor void static FnSetGraphics(Graphics^ gr); //hlavička funkce private: Graphics^ graphics; }; }//namespace
Upravíme Source soubor MyClass2.cpp
#include "stdafx.h" #include "MyClass2.h" namespace FormPrintDemo { Class2::Class2(){}; void Class2::FnSetGraphics(Graphics^ gr) { graphics = gr; //tělo funkce }; }
Doplníme reference na knihovny v Stdafx.h, budou se kompilovat pouze 1x.
#pragma once #using <System.dll> #using <System.Windows.Forms.dll> using namespace System; using namespace System::Drawing; using namespace System::Windows::Forms; using namespace Microsoft::VisualBasic::PowerPacks; using namespace System::Drawing::Drawing2D; namespace sd = System::Drawing ; namespace swf = System::Windows::Forms; namespace sri = System::Runtime::InteropServices;
Stejný postup bude u funkce
FnRealPageSettingsBounds(RealPageSetting); a také u
funkce
FnDrawBachgRoundImage(control.BackgroundImage,control.BackgroundImageLayout,RealPageSetting);.
Vytvoříme další hlavičkový a source soubor MyClassImage.h a
MyClassImage.cpp. Hlavičkový soubor MyClass2.h bude vypadat takto:
#pragma once #include "MyClassImage.h" namespace FormPrintDemo { public ref class Class2 : MyClassImage //Class2 dědí z MyClassImage { public: Class2(); void static FnSetGraphics(Graphics^ gr); void static FnRealPageSettingsBounds(Rectangle RealPageSetting); void static FnDrawBachgRoundImage(Image ^image, swf::ImageLayout imagelayout, Rectangle rec ); private: static Graphics^ graphics; static Rectangle realPageSetting; }; }
Source soubor MyClass2.cpp:
#include "stdafx.h" #include "MyClass2.h" namespace FormPrintDemo { Class2::Class2(){}; //konstruktor void Class2::FnSetGraphics(Graphics^ gr) { graphics = gr; }; void Class2::FnRealPageSettingsBounds(Rectangle RealPageSetting) { realPageSetting = RealPageSetting; }; void Class2::FnDrawBachgRoundImage(Image ^image, swf::ImageLayout imagelayout, Rectangle rec ) { if(image == nullptr){return;} //v C# -> null DrawBachgRoundImageA(graphics, image, rec, imagelayout ); }; }//namespace
Obrázek na pozadí pro ovládací prvek
Upravíme soubor MyClassImage.h
#pragma once namespace FormPrintDemo { public ref class MyClassImage { protected : void DrawBachgRoundImageA(Graphics^ gr, Image^ image, Rectangle rec, swf::ImageLayout layout ); private: Brush^ DrawBachgRoundImage(Graphics^ gr, Image^ image, Rectangle rec, swf::ImageLayout layout); Image^ backgroundImage; ImageLayout imageLayout; Image ^image ; }; }
Upravíme soubor MyClassImage.cpp
#include "stdafx.h" #include "MyClassImage.h" namespace FormPrintDemo { void MyClassImage::DrawBachgRoundImageA(Graphics^ gr, Image^ image, Rectangle rec, swf::ImageLayout layout) { Brush ^imageBrush = DrawBachgRoundImage(gr , image , rec , layout); if (imageBrush != nullptr) { gr->FillRectangle(imageBrush, rec); delete imageBrush; } }//DrawBachgRoundImageA Brush^ MyClassImage::DrawBachgRoundImage(Graphics^ graphics, Image^ image, Rectangle rec, swf::ImageLayout layout) { this->backgroundImage = (Image^) image ; TextureBrush ^textureBrush = safe_cast<TextureBrush^>(nullptr); if (this->backgroundImage != nullptr) { double num1 = safe_cast<double>(rec.X); double num2 = safe_cast<double>(rec.Y); int num3 = 0; int num4 = 0; Image ^image = this->backgroundImage; WrapMode wrapMode = WrapMode::Clamp; Bitmap ^bitmap = safe_cast<Bitmap^>(nullptr); this->imageLayout = layout; switch (this->imageLayout) { case ImageLayout::Tile: wrapMode = WrapMode::Tile; break; case ImageLayout::Center: num3 = rec.Width - this->backgroundImage->Width; if (num3 > 0) num1 = safe_cast<double>(rec.X) + safe_cast<double>(num3) / 2.0; num4 = rec.Height - this->backgroundImage->Height; if (num4 > 0) { num2 = safe_cast<double>(rec.Y) + safe_cast<double>(num4) / 2.0; break; } else break; case ImageLayout::Stretch: bitmap = gcnew Bitmap(rec.Width, rec.Height); graphics = Graphics::FromImage(safe_cast<Image^>(bitmap)); graphics->DrawImage(image, 0, 0, bitmap->Width, bitmap->Height); delete graphics; break; case ImageLayout::Zoom: double num5 = (double)(rec.Width) / safe_cast<double>(image->Width); double num6 = (double)(rec.Height) / (double)(image->Height); if (num5 > num6) { num1 = (double)rec.X + (num5 - num6) * (double)(image->Width) / 2.0; bitmap = gcnew Bitmap(int)(Math::Round(double)(image->Width) * num6)), rec.Height); } else { num2 = safe_cast<double>(rec.Y) + (num6 - num5) * safe_cast<double> (image->Height) / 2.0; bitmap = gcnew Bitmap(rec.Width,safe_cast<int(Math::Round(safe_cast<double>(image->Height) * num5))); } graphics = Graphics::FromImage(safe_cast<Image^>(bitmap)); graphics->DrawImage(image, 0, 0, bitmap->Width, bitmap->Height); delete graphics; break; }//switch if (bitmap != nullptr) { textureBrush = gcnew TextureBrush(safe_cast<Image^>(bitmap), wrapMode); delete bitmap; } else textureBrush = gcnew TextureBrush(image, wrapMode); Matrix ^transform = textureBrush->Transform; transform->Translate(safe_cast<float>(num1), safe_cast<float>(num2)); textureBrush->Transform = transform; } return safe_cast<Brush^>(textureBrush); } }
Poslední úprava před testem bude v Class1 v PdPrintPage(......) takto :
//Image pozadí formuláře (volaná funkce není statická) FormPrintDemo.Class2 class2 = new Class2(); class2.FnDrawBachgRoundImage(control.BackgroundImage, control.BackgroundImageLayout, RealPageSetting);
Provedeme sestavení, pokud jsme programovali bezchybně:
Sestavení bylo úspěšně dokončeno. Nové sestavení všeho: 3 úspěšně, 0 se nezdařilo, 0 přeskočeno
Test formuláře
Formulář nyní ozkoušíme:
- Můžeme měnit barvu pozadí formuláře
- Můžeme zadat Image pozadí (BackgroundImage)
- Můžeme měnit rozložení obrázku pozadí (BackgroundImageLayout -> None, Tile, Center, Zoom, Stretch)
- Můžeme zapnou nebo vypnout zobrazení ohraničení na stránce

Není možné vysvětlovat činnost kódu FnDrawBachgRoundImage(.....), rozbor kódu by zabral samostatný výklad. Pokračování v příštím díle, kde bude rozebrána logika výběru ovládacích prvků.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 97x (773.96 kB)
Aplikace je včetně zdrojových kódů v jazyce C#