usercontrol
-
Hallo Forum,
ich brauche dringend (aus historischen Gründen) ein 7 Segmentelementdisplay auf c++/cli (VS 2008) Basis und habe daher ein solches Beispiel einfach kurzer Hand mal umgeschrieben(https://www.codeproject.com/Articles/37800/Seven-segment-LED-Control-for-NET).#pragma once using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; using namespace System::Drawing::Drawing2D; namespace SevenSegment { /// <summary> /// Zusammenfassung für SingleSegment /// </summary> public ref class SingleSegment : public System::Windows::Forms::UserControl { public: array<System::Drawing::Point^,2>^ segPoints; public: array<System::Drawing::Point>^ copiedsegPoints; public: SingleSegment(void) { InitializeComponent(); this->SuspendLayout(); this->Name = "SevenSegment"; this->Size = System::Drawing::Size(32, 64); this->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &SingleSegment::SevenSegment_Paint); this->Resize += gcnew System::EventHandler(this, &SingleSegment::SevenSegment_Resize); this->ResumeLayout(false); this->TabStop = false; this->Padding = System::Windows::Forms::Padding(4, 4, 4, 4); this->DoubleBuffered = true; segPoints = gcnew array<System::Drawing::Point^,2> (7,7); for (int i = 0; i < 7; i++) {for (int j = 0; j < 7; j++) segPoints[i,j] = gcnew Point(0,0); // copiedsegPoints[i] =Point(0,0); } copiedsegPoints = gcnew array<System::Drawing::Point>(6); RecalculatePoints(); } protected: /// <summary> /// Verwendete Ressourcen bereinigen. /// </summary> ~SingleSegment() { if (components) { delete components; } } private: /// <summary> /// Erforderliche Designervariable. /// </summary> System::ComponentModel::Container ^components; #pragma region Windows Form Designer generated code /// <summary> /// Erforderliche Methode für die Designerunterstützung. /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. /// </summary> void InitializeComponent(void) { this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; } #pragma endregion /// <summary> /// Recalculate the points that represent the polygons of the /// seven segments, whether we're just initializing or /// changing the segment width. /// </summary> private: void RecalculatePoints() { int halfHeight = gridHeight / 2, halfWidth = elementWidth / 2; int p = 0; segPoints[p,0]->X = elementWidth + 1; segPoints[p,0]->Y = 0; segPoints[p,1]->X = gridWidth - elementWidth - 1; segPoints[p,1]->Y = 0; segPoints[p,2]->X = gridWidth - halfWidth - 1; segPoints[p,2]->Y = halfWidth; segPoints[p,3]->X = gridWidth - elementWidth - 1; segPoints[p,3]->Y = elementWidth; segPoints[p,4]->X = elementWidth + 1; segPoints[p,4]->Y = elementWidth; segPoints[p,5]->X = halfWidth + 1; segPoints[p,5]->Y = halfWidth; p++; segPoints[p,0]->X = 0; segPoints[p,0]->Y = elementWidth + 1; segPoints[p,1]->X = halfWidth; segPoints[p,1]->Y = halfWidth + 1; segPoints[p,2]->X = elementWidth; segPoints[p,2]->Y = elementWidth + 1; segPoints[p,3]->X = elementWidth; segPoints[p,3]->Y = halfHeight - halfWidth - 1; segPoints[p,4]->X = 4; segPoints[p,4]->Y = halfHeight - 1; segPoints[p,5]->X = 0; segPoints[p,5]->Y = halfHeight - 1; p++; segPoints[p,0]->X = gridWidth - elementWidth; segPoints[p,0]->Y = elementWidth + 1; segPoints[p,1]->X = gridWidth - halfWidth; segPoints[p,1]->Y = halfWidth + 1; segPoints[p,2]->X = gridWidth; segPoints[p,2]->Y = elementWidth + 1; segPoints[p,3]->X = gridWidth; segPoints[p,3]->Y = halfHeight - 1; segPoints[p,4]->X = gridWidth - 4; segPoints[p,4]->Y = halfHeight - 1; segPoints[p,5]->X = gridWidth - elementWidth; segPoints[p,5]->Y = halfHeight - halfWidth - 1; p++; segPoints[p,0]->X = elementWidth + 1; segPoints[p,0]->Y = halfHeight - halfWidth; segPoints[p,1]->X = gridWidth - elementWidth - 1; segPoints[p,1]->Y = halfHeight - halfWidth; segPoints[p,2]->X = gridWidth - 5; segPoints[p,2]->Y = halfHeight; segPoints[p,3]->X = gridWidth - elementWidth - 1; segPoints[p,3]->Y = halfHeight + halfWidth; segPoints[p,4]->X = elementWidth + 1; segPoints[p,4]->Y = halfHeight + halfWidth; segPoints[p,5]->X = 5; segPoints[p,5]->Y = halfHeight; p++; segPoints[p,0]->X = 0; segPoints[p,0]->Y = halfHeight + 1; segPoints[p,1]->X = 4; segPoints[p,1]->Y = halfHeight + 1; segPoints[p,2]->X = elementWidth; segPoints[p,2]->Y = halfHeight + halfWidth + 1; segPoints[p,3]->X = elementWidth; segPoints[p,3]->Y = gridHeight - elementWidth - 1; segPoints[p,4]->X = halfWidth; segPoints[p,4]->Y = gridHeight - halfWidth - 1; segPoints[p,5]->X = 0; segPoints[p,5]->Y = gridHeight - elementWidth - 1; p++; segPoints[p,0]->X = gridWidth - elementWidth; segPoints[p,0]->Y = halfHeight + halfWidth + 1; segPoints[p,1]->X = gridWidth - 4; segPoints[p,1]->Y = halfHeight + 1; segPoints[p,2]->X = gridWidth; segPoints[p,2]->Y = halfHeight + 1; segPoints[p,3]->X = gridWidth; segPoints[p,3]->Y = gridHeight - elementWidth - 1; segPoints[p,4]->X = gridWidth - halfWidth; segPoints[p,4]->Y = gridHeight - halfWidth - 1; segPoints[p,5]->X = gridWidth - elementWidth; segPoints[p,5]->Y = gridHeight - elementWidth - 1; p++; segPoints[p,0]->X = elementWidth + 1; segPoints[p,0]->Y = gridHeight - elementWidth; segPoints[p,1]->X = gridWidth - elementWidth - 1; segPoints[p,1]->Y = gridHeight - elementWidth; segPoints[p,2]->X = gridWidth - halfWidth - 1; segPoints[p,2]->Y = gridHeight - halfWidth; segPoints[p,3]->X = gridWidth - elementWidth - 1; segPoints[p,3]->Y = gridHeight; segPoints[p,4]->X = elementWidth + 1; segPoints[p,4]->Y = gridHeight; segPoints[p,5]->X = halfWidth + 1; segPoints[p,5]->Y = gridHeight - halfWidth; } static int gridHeight = 80; static int gridWidth = 48; static int elementWidth = 10; static float italicFactor = 0.0F; static System::Drawing::Color colorBackground = System::Drawing::Color::DarkGray; static System::Drawing::Color colorDark = System::Drawing::Color::DimGray; static System::Drawing::Color colorLight = System::Drawing::Color::Red; /// <summary> /// Background color of the 7-segment display. /// </summary> public: property System::Drawing::Color ColorBackground { System::Drawing::Color get() { return colorBackground; } void set(System::Drawing::Color value) { colorBackground = value; this->Invalidate(); } } /// <summary> /// Color of inactive LED segments. /// </summary> property System::Drawing::Color ColorDark { System::Drawing::Color get() { return colorDark; } void set(System::Drawing::Color value) { colorDark = value; this->Invalidate(); } } /// <summary> /// Color of active LED segments. /// </summary> property System::Drawing::Color ColorLight { System::Drawing::Color get() { return colorLight; } void set(System::Drawing::Color value) { colorLight = value; this->Invalidate(); } } /// <summary> /// Width of LED segments. /// </summary> property int ElementWidth { int get() { return elementWidth; } void set(int value) { elementWidth = value; RecalculatePoints(); this-> Invalidate(); } } /// <summary> /// Shear coefficient for italicizing the displays. Try a value like -0.1. /// </summary> property float ItalicFactor { float get() { return italicFactor; } void set(float value) { italicFactor = value; this->Invalidate(); } } private: void SevenSegment_Resize(Object^ sender, EventArgs^ e) { this->Invalidate(); } protected: virtual void OnPaddingChanged(EventArgs^ e) override { //base::OnPaddingChanged(e); this->Invalidate(); } virtual void OnPaintBackground(PaintEventArgs^ e) override { //base::OnPaintBackground(e); e->Graphics->Clear(colorBackground); } /// <summary> /// These are the various bit patterns that represent the characters /// that can be displayed in the seven segments. Bits 0 through 6 /// correspond to each of the LEDs, from top to bottom! /// </summary> public: enum class ValuePattern { None = 0x0, Zero = 0x77, One = 0x24, Two = 0x5D, Three = 0x6D, Four = 0x2E, Five = 0x6B, Six = 0x7B, Seven = 0x25, Eight = 0x7F, Nine = 0x6F, A = 0x3F, B = 0x7A, C = 0x53, D = 0x7C, E = 0x5B, F = 0x1B, G = 0x73, H = 0x3E, J = 0x74, L = 0x52, N = 0x38, O = 0x78, P = 0x1F, Q = 0x2F, R = 0x18, T = 0x5A, U = 0x76, Y = 0x6E, Dash = 0x8, Equals = 0x48 } ; private: static String^ theValue = ""; /// <summary> /// Character to be displayed on the seven segments. Supported characters /// are digits and most letters. /// </summary> public: property String^Value { String^ get() { return theValue; } void set(String^ value) { customPattern = 0; if (value != "") { //is it an integer? bool success = false; try { int tempValue = Convert::ToInt32(value); if (tempValue > 9) tempValue = 9; if (tempValue < 0) tempValue = 0; switch (tempValue) { case 0: customPattern = (int)ValuePattern::Zero; break; case 1: customPattern = (int)ValuePattern::One; break; case 2: customPattern = (int)ValuePattern::Two; break; case 3: customPattern = (int)ValuePattern::Three; break; case 4: customPattern = (int)ValuePattern::Four; break; case 5: customPattern = (int)ValuePattern::Five; break; case 6: customPattern = (int)ValuePattern::Six; break; case 7: customPattern = (int)ValuePattern::Seven; break; case 8: customPattern = (int)ValuePattern::Eight; break; case 9: customPattern = (int)ValuePattern::Nine; break; } success = true; } catch(Exception ^e) { }; if (!success) { try { //is it a letter? String^ tempString = Convert::ToString(value); switch (tempString->ToLower()[0] ) { case 'a': customPattern = (int)ValuePattern::A; break; case 'b': customPattern = (int)ValuePattern::B; break; case 'c': customPattern = (int)ValuePattern::C; break; case 'd': customPattern = (int)ValuePattern::D; break; case 'e': customPattern = (int)ValuePattern::E; break; case 'f': customPattern = (int)ValuePattern::F; break; case 'g': customPattern = (int)ValuePattern::G; break; case 'h': customPattern = (int)ValuePattern::H; break; case 'j': customPattern = (int)ValuePattern::J; break; case 'l': customPattern = (int)ValuePattern::L; break; case 'n': customPattern = (int)ValuePattern::N; break; case 'o': customPattern = (int)ValuePattern::O; break; case 'p': customPattern = (int)ValuePattern::P; break; case 'q': customPattern = (int)ValuePattern::Q; break; case 'r': customPattern = (int)ValuePattern::R; break; case 't': customPattern = (int)ValuePattern::T; break; case 'u': customPattern = (int)ValuePattern::U; break; case 'y': customPattern = (int)ValuePattern::Y; break; case '-': customPattern = (int)ValuePattern::Dash; break; case '=': customPattern = (int)ValuePattern::Equals; break; } } catch(Exception ^e) { } } } theValue = value; this->Invalidate(); } } private: static int customPattern = 0; /// <summary> /// Set a custom bit pattern to be displayed on the seven segments. This is an /// integer value where bits 0 through 6 correspond to each respective LED /// segment. /// </summary> public: property int CustomPattern { int get() { return customPattern; } void set(int value) { customPattern = value; this->Invalidate(); } } private: static bool showDot = true, dotOn = false; /// <summary> /// Specifies if the decimal point LED is displayed. /// </summary> public: property bool DecimalShow { bool get() { return showDot; } void set(bool value) { showDot = value; this->Invalidate(); } } /// <summary> /// Specifies if the decimal point LED is active. /// </summary> property bool DecimalOn { bool get() { return dotOn; } void set(bool value) { dotOn = value; this->Invalidate(); } } private: void SevenSegment_Paint(Object^ sender, PaintEventArgs^e) { int useValue = customPattern; int counter; //MessageBox::Show("Painting"); Brush^ brushLight = gcnew SolidBrush(colorLight); Brush^ brushDark = gcnew SolidBrush(colorDark); // Define transformation for our container... RectangleF srcRect = RectangleF(0.0F, 0.0F, gridWidth, gridHeight); RectangleF destRect = RectangleF(Padding.Left, Padding.Top, this->Width - Padding.Left - Padding.Right, this->Height - Padding.Top - Padding.Bottom); // Begin graphics container that remaps coordinates for our convenience GraphicsContainer^ containerState = e->Graphics->BeginContainer(destRect, srcRect, GraphicsUnit::Pixel); Matrix^ trans = gcnew Matrix(); trans->Shear(italicFactor, 0.0F); e->Graphics->Transform = trans; e->Graphics->SmoothingMode = SmoothingMode::AntiAlias; e->Graphics->PixelOffsetMode = PixelOffsetMode::Default; // Draw elements based on whether the corresponding bit is high for(counter = 0; counter < 6; counter ++) { copiedsegPoints[counter].X = segPoints[0,counter]->X; copiedsegPoints[counter].Y = segPoints[0,counter]->Y; } e->Graphics->FillPolygon( (useValue & 0x1) == 0x1 ? brushLight : brushDark, copiedsegPoints) ; for(counter = 0; counter < 6; counter ++) { copiedsegPoints[counter].X = segPoints[1,counter]->X; copiedsegPoints[counter].Y = segPoints[1,counter]->Y; } e->Graphics->FillPolygon((useValue & 0x2) == 0x2 ? brushLight : brushDark, copiedsegPoints); for(counter = 0; counter < 6; counter ++) { copiedsegPoints[counter].X = segPoints[2,counter]->X; copiedsegPoints[counter].Y = segPoints[2,counter]->Y; } e->Graphics->FillPolygon((useValue & 0x4) == 0x4 ? brushLight : brushDark, copiedsegPoints); for(counter = 0; counter < 6; counter ++) { copiedsegPoints[counter].X = segPoints[3,counter]->X; copiedsegPoints[counter].Y = segPoints[3,counter]->Y; } e->Graphics->FillPolygon((useValue & 0x8) == 0x8 ? brushLight : brushDark, copiedsegPoints); for(counter = 0; counter < 6; counter ++) { copiedsegPoints[counter].X = segPoints[4,counter]->X; copiedsegPoints[counter].Y = segPoints[4,counter]->Y; } e->Graphics->FillPolygon((useValue & 0x10) == 0x10 ? brushLight : brushDark, copiedsegPoints); for(counter = 0; counter < 6; counter ++) { copiedsegPoints[counter].X = segPoints[5,counter]->X; copiedsegPoints[counter].Y = segPoints[5,counter]->Y; } e->Graphics->FillPolygon((useValue & 0x20) == 0x20 ? brushLight : brushDark, copiedsegPoints); for(counter = 0; counter < 6; counter ++) { copiedsegPoints[counter].X = segPoints[6,counter]->X; copiedsegPoints[counter].Y = segPoints[6,counter]->Y; } e->Graphics->FillPolygon((useValue & 0x40) == 0x40 ? brushLight : brushDark, copiedsegPoints); if (showDot) e->Graphics->FillEllipse(dotOn ? brushLight : brushDark, gridWidth - 1, gridHeight - elementWidth + 1, elementWidth, elementWidth); e->Graphics->EndContainer(containerState); } // void }; }
Während das Ganze mit C# unproblematisch ist, scheint es mit C++/cli nur irgendwie zu funktionieren. Sobald ich ein weiteres Segment mittels des Forms- Designers in ein Form hinzufüge, übernehmen die bereits hinzugefügten Elemente die Eigenschaften des zuletzt hinzugefügten Elements. Vielleicht kann mir ja hier jemand weiterhelfen.
-
Also das Ganze scheint doch irgendwie zu funktionieren – man muss aber nach jeder Werteänderung nochmal „->Update“ aufrufen, damit der Wert auch in die Klasse geschrieben wird. Andernfalls beobachtet man, dass beim Aufruf des PaintEvents jeweils nur der Wert des zuletzt bearbeiteten Control ankommt.
So geht’s erst mal:void button1_Click(System::Object^ sender, System::EventArgs^ e) { this->sevenSegment1->Value = L"5"; this->sevenSegment1->Update(); this->sevenSegment2->Value = L"6"; this->sevenSegment2->Update(); }