4. díl - Tisk formuláře a ovládacích prvků Windows Forms

C# .NET Windows Forms 4. díl - Tisk formuláře a ovládacích prvků Windows Forms

V minulém díle jsme dokončili programování formuláře a dnes ukáži jakým stylem vybrat ovládací prvky umístěné na formuláři. Ve druhém díle jsme vytvořili hlavičku funkce:

private void PrintControls(System.Windows.Forms.Control ctrl, int x0, int y0){}

Tuto funkci doplníme kódem:

using System.Diagnostics;

//vytvoří setříděnou kolekci prvků a podle jejich skutečné polohy na formuláři
private void PrintControls(System.Windows.Forms.Control ctrl, int x0, int y0)
{
    int nbCtrl = ctrl.Controls.Count;
    int[] yPos = new int[nbCtrl];
    System.Windows.Forms.Control[] controls = new System.Windows.Forms.Control[nbCtrl];
    //načte prvky do kolekce
    for (int i = 0; i < nbCtrl; i++)
    {
        controls[i] = ctrl.Controls[i];
        yPos[i] = ctrl.Controls[i].Location.Y;
    }
    //setřídí prvky podle souřadnice Y
    System.Array.Sort(yPos, controls);
 //   Debug.Print("\r\n");              //Pro testy
    for (int i = 0; i < nbCtrl; i++)
    {
        // skutečná poloha prvků  jsou započítány okraje tištěného formuláře
        PrintControl(controls[i], x0 + controls[i].Location.X, y0 + controls[i].Location.Y);
 //       Debug.Print(i.ToString() + "     " + controls[i].Name.ToString());  //pro testy
    }
}

Pro testy doplníme záhlaví naší třídy System.Diagnostics a naši funkci Debug.Print(.....) a budeme
sledovat výstup naší funkce. Tato funkce je volána pomocí rekurze, počet průchodů je dán rozložením a počtem uživatelských prvků. Pro názornost ukázky je použita plná verze programu.

Nejlépe vystihuje funkci tato ukázka. Stojí za povšimnutí pouze jeden průchod funkcí pro shapeContainer.

Prvky formuláře Výstup ladění
// funkce rozdělí prvky na rodiče a jejich děti
// v případě dětí je provedena rekurze
private void PrintControl(Control ctrl, int locationX, int locationY)
{
    if (ctrl.Visible)
    {
        bool scanForChildControls = false;
        // Vytisknout ovládací prvky na formuláři
        PrintOneControl(ctrl, ParentControlPrinting.BeforeChilds, locationX, locationY,
            out scanForChildControls);
        // Vytisknout obsažené ovládací prvky (děti)
        if (scanForChildControls)
        {
            PrintControls(ctrl, locationX, locationY);  //Zde je volaná rekurze pro děti
            PrintOneControl(ctrl, ParentControlPrinting.AfterChilds, locationX, locationY,
            out scanForChildControls);
        }
    }
}

Další naše funkce vyloučí uživatelské prvky, které nechceme tisknout a generuje funkce k tisku.

private void PrintOneControl(Control ctrl, ParentControlPrinting typePrint,
                int locationX, int locationY, out bool scanForChildControls)
    {
        scanForChildControls = true;
        string s = ctrl.GetType().ToString();
        bool founded = false;
        //vylučuji vybrané uživatelské prvky z tisku
        if (deletePrintControl.Any(sType => s.IndexOf("." + sType, StringComparison.Ordinal) >= 0))
        {
            founded = true;
            scanForChildControls = false;
        }
        //Process other type of control, beginning at the end of the list (use last add for a type)
        //Musíme začít -> prvý do kolekce -> prvý k tisku
        if (!founded)
            for (int i = delegatesforControls.Count - 1; i >= 0; i--)  // od konce na začátek
            {
                DelegateforControls d = (DelegateforControls)delegatesforControls[i];
                if (s.EndsWith(d.Typ))
                {
                    d.PrintFunction(ctrl, typePrint, locationX, locationY, out scanForChildControls);
                    //Debug.Print(d.Typ);
                    break;
                }
            }
    }

Tabulka ukazuje jak generujeme funkce pro tisk.

Pořadí tisku Pokud se dobře díváte, některé funkce jsou
tu dvakrát a na našem formuláři je tento prvek pouze jednou.

Pokud má uživatelský prvek vlastnost na sebe vázat jiné uživatelské prvky (například GroupBox, UserControl, TabControl, PictureBox), další druhý průchod pro tisk je blokován pomocí testu (enum ParentControl­Printing) v kódu pro daný uživatelský prvek.

Příklad:

if (typePrint == ParentControlPrinting.BeforeChilds)
{
        MyClass2.PrintPictureBox(pb, x1, y1, width, height);
}

Poslední funkce nám musí ořezat přesahující části ovládacího prvku (dítěte) uloženého na rodiči, například GroupBox, Panel a podobně, na kterých je uložen TextBox, který přesahuje přes rodiče.

//ořeže velikost těchto dětských prvků o část , které přesahují rodiče
private void TrimChild(Control ctrl, ref int x1, ref int y1 , out int width ,out int height )
 {
   width = ctrl.Width; height = ctrl.Height;
   if (ctrl.Parent == this.control)
   {
      RecRodic = new Rectangle(x1, y1, width, height);
      return;
   }
   else
   {
     Rectangle rec = new Rectangle(x1, y1, ctrl.Width, ctrl.Height);

     Rectangle rr = Rectangle.Intersect(rec, RecRodic);
     x1 = rr.Left;
     y1 = rr.Top;
     width = rr.Width;
     height = rr.Height;
   }
 }

Poslední funkce naší třídy Class1 již volají definované ovládací prvky v konstruktoru Class1. Hlavičky těchto funkcí jsme již vytvořili při definování konstruktoru. Nyní je doplníme kódem. Tento je stejný pro ovládací prvky, které nemohou být kontejnerem pro další prvky. Ovládací prvky, které jsou kontejnerem pro další prvky, mají v kódu přidány 2 řádky, důvody jsem uvedl při výkladu poslední tabulky.

Funkce PrinTextBox

#region "Tiskne TextBox"
private void PrintTextBox(Control ctrl,ParentControlPrinting typePrint, int x1, int y1,
                          out bool ScanForChildControls)
{
        //prvek nemůže mít kontejner to znamená nelze na něho uložit další ovládací prvek
        ScanForChildControls = false;
        int width = 0; int height = 0;
        TrimChild(ctrl, ref x1, ref y1, out width, out height);
        TextBox tb = (TextBox)ctrl;
        //Voláme funkci tisku pro TextBox
        MyClass2.FnPrintTextBox(tb, x1, y1, width, height);

}//PrintTextBox
 #endregion

Funkce PrintShape

#region "Tiskne LineShape OvalShape RectangleShape"
private void PrintShape(Control ctrl,ParentControlPrinting typePrint,int x1, int y1,
                        out bool ScanForChildControls)
{
      ScanForChildControls = false;
      int width = 0; int height = 0;
      TrimChild(ctrl, ref x1, ref y1, out width, out height);
      Kreslivbshape pPack = new Kreslivbshape();
      pPack.PrintShape(graphics, ctrl, x1, y1 , RealPageSetting);
}
 #endregion

Ukázka funkce pro UserControl

#region  "UserControl"
//jediná funkce public volá se externě z FormPrintDemo (není dodělána).
//fp.AddDelegateToPrintControlEx("PZ.Tisky.UserControl1", fp.PrintUserControl);
/*
public void PrintUserControl(Control ctrl,ParentControlPrinting typePrint,int x1, int y1,
                            out bool scanForChildControls)
{
     scanForChildControls = true; //má kontejner , může vázat další prvky
     int width = 0; int height = 0;
     TrimChild(ctrl, ref locationX, ref locationY, out width, out height);
     UserControl usc = (UserControl)ctrl;
     if (typePrint == ParentControlPrinting.BeforeChilds)
     {
         classTisk.FnPrintUserControl(usc, locationX, locationY, width, height);
     }
}
*/

Do Class1 nebudeme již psát žádný další kód. Musíme napsat hlavičky do dll třídy MyClass2 a zkusíme provést kompilaci.

Dopsání kódu do MyClass2

//header soubor MyClass2.h a dopíšeme funkci
   public :
        void FnPrintTextBox(swf::TextBox^ tb,int x1, int y1 , int w1 , int h1);

//vytvoříme novou třídu v header soubor MyClass2.h a dopíšeme funkci
public ref class Kreslivbshape{
   public:
       void PrintShape(Graphics^ gr, Control ^control, int x, int y , Rectangle rec);

   private:
       Graphics^ graphics;
       int count;
       int x0;
       int y0;
};//Kresli prvky

//source soubor MyClass2.cpp
//tisk TextBox
void Class2::FnPrintTextBox(swf::TextBox^ tb,int x1, int y1 , int w1 , int h1)
{
};

//tisk LineShape OvalShape RectangleShape
void Kreslivbshape::PrintShape(Graphics^ gr, Control ^control, int x, int y , Rectangle rec )
{
};

Sestavíme řešení (provedeme kompilaci) v okně výstupu se zobrazí:

Sestavení bylo úspěšně dokončeno.
========== Nové sestavení všeho: 3 úspěšně, 0 se nezdařilo, 0 přeskočeno ==========

V Dalším díle pouze doplníme nové funkce ve třídě MyClass2 a jsme hotoví. Pokračování příště.


 

Stáhnout

Staženo 70x (72.32 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

  Aktivity (1)

Článek pro vás napsal zpavlu
Avatar
C# a C++

Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!


 



 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!