VC ++ 2008 Kindelemente vom Kindelement vom tableLayoutPanel ansprechen?
-
Hallo, bin der Neue.
Ich hoffe, man kann das lesen, denn meine Browser sind nicht kompatibel. Das Eingabefenster ist schwarz auf schwarz. Abschicken geht im Chrome auch nicht, habe mir ne Mail zum iPhone geschickt. Ging auch nicht.
Jetzt mal ein Versuch im Internext Explorer...Ich habe in VC ++ 2008 mit Forms ein tableLayoutPanel, welches ich mit benutzerdefinieren Klassen befülle.
So sieht eine dieser Klassen aus:
ref class FlatButton : public System::Windows::Forms::Button {public:FlatButton(){this->FlatStyle = System::Windows::Forms::FlatStyle::System;};}; ref class Flat2Button : public FlatButton {public:Flat2Button(){this->Font = (gcnew System::Drawing::Font(L"Webdings", 12, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point, static_cast<System::Byte>(2)));};}; ref class TimerZeile : public System::Windows::Forms::TableLayoutPanel { ref class nam : public System::Windows::Forms::TextBox {public: nam(){this->Size = System::Drawing::Size(134, 20);this->Text = L"neue Eieruhr";};}; ref class a15 : public FlatButton {public: a15(){this->Text = L"15";};}; ref class aa1 : public FlatButton {public: aa1(){this->Text = L"1";};}; ref class aa3 : public FlatButton {public: aa3(){this->Text = L"3";};}; ref class aa9 : public FlatButton {public: aa9(){this->Text = L"9";};}; ref class a12 : public FlatButton {public: a12(){this->Text = L"12";};}; ref class a24 : public FlatButton {public: a24(){this->Text = L"24";};}; ref class a48 : public FlatButton {public: a48(){this->Text = L"48";};}; ref class tim : public System::Windows::Forms::MaskedTextBox {public: tim(){this->InsertKeyMode = System::Windows::Forms::InsertKeyMode::Overwrite;this->Mask = L"900:00:00";};}; ref class sta : public Flat2Button {public: sta(){this->Text = L"4q";};}; ref class del : public Flat2Button {public: del(){this->Text = L"r";};}; public: TimerZeile(){ this->ColumnCount = 11; this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 140))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 29))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 25))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 24))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 24))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 29))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 29))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 29))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 61))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 48))); this->ColumnStyles->Add((gcnew System::Windows::Forms::ColumnStyle(System::Windows::Forms::SizeType::Absolute, 22))); this->Controls->Add(gcnew TimerZeile::nam, 0, 0);this->Controls->Add(gcnew TimerZeile::a15, 1, 0);this->Controls->Add(gcnew TimerZeile::aa1, 2, 0); this->Controls->Add(gcnew TimerZeile::aa3, 3, 0);this->Controls->Add(gcnew TimerZeile::aa9, 4, 0);this->Controls->Add(gcnew TimerZeile::a12, 5, 0); this->Controls->Add(gcnew TimerZeile::a24, 6, 0);this->Controls->Add(gcnew TimerZeile::a48, 7, 0);this->Controls->Add(gcnew TimerZeile::tim, 8, 0); this->Controls->Add(gcnew TimerZeile::sta, 9, 0);this->Controls->Add(gcnew TimerZeile::del, 10, 0);this->Location = System::Drawing::Point(3, 3); this->RowCount = 1;this->RowStyles->Add((gcnew System::Windows::Forms::RowStyle(System::Windows::Forms::SizeType::Absolute, 26))); this->Size = System::Drawing::Size(459, 26); } };
Dann habe ich versucht, den Buttons ein Klick-Event anzufügen. Das scheiterte nach einigen Versuchen schließlich daran, dass ich ja die Instanz des Buttons brauche, übergeben wird als sender aber die Klasse.
Also habe ich in der Funktion, wo diese Zeilen eingefügt werden, folgenden Code:
this->tableLayoutPanel1->Controls->Add(thetimers[i] = gcnew TimerZeile,0,this->tableLayoutPanel1->RowCount-1); thetimers[i]->Click += gcnew System::EventHandler(this, &Form1::DeleteTimer);
Das funktioniert soweit, aber ich will ja nicht, dass die Zeile der sender ist, sondern der Button, denn ich muss ja auch die Textboxen verändern können. Nun habe ich im Debugmodus herausgefunden, dass soetwas wie dieses hier funktionieren könnte, tut es natürlich nicht:
thetimers[i]->Controls->System::Windows::Forms::Control::ControlCollection^->System::Windows::Forms::ArrangedElementCollection^->_innerList[10]-Click += gcnew System::EventHandler(this, &Form1::DeleteTimer);
Gibt es da eine Möglichkeit, auf die Kindelemente zuzugreifen oder komme ich um ein präziseres Array nicht herum?
Das Programm soll ein Mehrfach-Wecker werden.
-
Wie du schon selbst erkannt hast, mußt du jeweils den Button-Instanzen das
Click
-Ereignis zuweisen.Es ist jedoch auch die Frage, warum du eigene Klassen für jedes der Unterelemente dafür erzeugst?
Die Texte kannst du auch bei der Erzeugung der Unterelemente (z.B.FlatButton
) zuweisen.Und dazu dann das
Click
-Ereignis zuweisen. Hier ist auch die Frage, ob du eineClick
-Funktion für alle Buttons haben möchtest oder jeweils individuelle?Für letzteres am besten dafür dann eine Funktion erzeugen, z.B.
FlatButton^ CreateButton(const wchar* text, System::EventHandler on_click) { FlatButton button = gcnew FlatButton(); button->Text = text; button->Click += on_click; return button; }
Und dann so aufrufen:
this->Controls->Add(CreateButton(L"15", gcnew System::EventHandler(this, &Form1::DeleteTimer)), 1, 0); // ...
Edit:
Es müßte auch möglich sein, nur&Form1::DeleteTimer
als Parameter an die Funktion zu übergeben und dann innerhalb dieser dann denEventHandler
zu erzeugen - der Parametertyp ist dann ein Memberfunktionszeigervoid (Form1::*)(System::Object ^ sender, EventArgs ^ e)
(oder so ähnlich ;-).
PS: Da ich selber hauptsächlich C# und C++, anstatt C++/CLI, programmiere, kann es sein, daß der Code noch Fehler enthält (z.B. fehlende
^
oder falsche Datentypen bei den Parametern).Außerdem ist C++/CLI nicht für die GUI-Programmierung gedacht, s.a. den gepinnten Artikel Windows Forms und Visual C++ MACHT KEINEN SINN!
-
Danke erstmal, aber so ganz bekomme ich es noch nicht hin.
Nach einigen Versuchen (2D-Arrays ala Control^,2 wollen in Cli einfach nicht. Er sagt er immer, er könne Void nicht in Control konvertieren.) habe ich nun das Array thetimers passend erweitert:public: static array<array<Control^>^>^ thetimers;
In einer Funktion wird das Array auch erstellt:
thetimers= gcnew array<array<Control^>^>(999);for (int i = 0; i < thetimers->Length; i++) {thetimers[i]=gcnew array <Control^>(11);};
Den Befehl zum Zeile-hinzufügen ändere ich so:
this->tableLayoutPanel1->Controls->Add(thetimers[i][0] = gcnew TimerZeile(i),0,this->tableLayoutPanel1->RowCount-1);
Jetzt kann ich im Kontruktor (der nun auch ne Klammer hat) schreiben:
thetimers[i][11] = gcnew TimerZeile::del, 10, 0);
Soweit, so gut. Die Instanzen sind nun ansprechbar.
Wenn ich jetzt versuche, in der gleichen Zeile einen EventHandler hinzuzufügen, will er, dass die aufgerufene Funktion
statisch ist. Wenn ich darauf eingehe, will er das woanders auch und noch andere Fehler breiten sich aus wie ein Krebsgeschwür.Also habe ich deinen Tipp versucht, indem ich
ref class del : public Flat2Button {public: del(System::EventHandler^ on_click){this->Text = L"r";this->Click += on_click;};};
und
this->Controls->Add(thetimers[i][11] = gcnew TimerZeile::del(gcnew System::EventHandler(this, &Form1::DeleteTimer)), 10, 0);
schreibe, aber dann entstehen diese Fehler:
error C2440: 'Initialisierung': 'The_TimerbyRikku33::Form1::TimerZeile ^const ' kann nicht in 'The_TimerbyRikku33::Form1 ^' konvertiert werden
error C3754: Delegatkonstruktor: Die Memberfunktion "The_TimerbyRikku33::Form1::DeleteTimer" kann nicht für eine Instanz vom Typ "The_TimerbyRikku33::Form1::TimerZeile ^const " aufgerufen werden.Da ist aber nichts als const definiert.
Die Sache ist die: Ich versuche die Funktion, wo die Zeilenerstellung in Auftrag gegeben wird, möglichst klein zu halten.
Ich kann auch versuchen, dort die Event-Handler zu registrieren, aber in jedem Fall meckert er immer, dass ein Delegatkontruktor zwei Argumente will und mit System::EventArgs::Empty will er auch irgendwie nicht.
Ich glaube, ich hatte das die Tage schon mal hinbekommen mit einer zweiten Funktion auch der Klasse heraus.
-
Tja, so wird das wohl nichts, da fehlen einfach zu viele Grundlagen!
Am besten wäre wirklich, wenn du die GUI mit C# umsetzt (die Syntax ist deutlich einfacher zu verstehen) - und da können dir auch mehr Leute bei helfen.
-
Was habt ihr bloß alle für ein Problem mit Windows Forms?
Mir wäre es auch lieber, wenn ich Fenster selber bauen könnte, aber ist sowieso alles kein Assembler, also was macht das schon?
Zum Thema Grundlagen: Wenn ich kein Buch kaufen, will, welche wären das?
Also als Kind machte ich Basic. Als Jugendlicher JavaScript. Zwischendurch auch viel VB in Excel. Ich hab zwischendurch auch mal dieses neue Basic probiert, aber da liefen die Programme nur bei jedem zweiten Start vernünftig und die Grafik war trotzdem nicht originalgetreu.
Warum die 2D-Arrays nicht funktionieren, verstehe ich auch. Stichwort verwaltet und nicht verwaltet. Wie ich mit Zeigern arbeiten soll und welche praktischen Beispiele mich vom Sinn dieser Übung überzeugen sollen, das würde mich mal interessieren.Google empfielt mir für meine Vorhaben immer C++ und da CLI nunmal kein C# ist, ist das doch ne einfache Entscheidung. Das Problem ist meines Erachtens nicht C++, sondern die veraltete Version. Mittlerweile scheint Google das aber ausreichend zu respektieren. Mein letztes Projekt war Kommunikation zwischen 2 Programmen mit Ports. In VC++ Express 2005 ging das nicht, weil die erforderlichen Bibliotheken nicht dabei waren, in 2008 funktioniert das, daher genügt mir das. 2010 benötigt Vista. Hab ich mir vorsichtshalber auch schon eingerichtet, aber VC++ noch nicht installiert.
Davor habe ich ein Zahlenratespiel in Forms gemacht, wobei dort auch ein Array vom Typ Label^ Verwendung findet. Wer mal schauen möchte:
[Link Text=Ratespiel.exe](Link Adresse=http://rikku33.bplaced.net/Ratespiel.exe)
-
OT:
Ich möchte das und das in C++ machen, kriege das aber nicht hin.Forum:
Mach das nicht, das macht nur Probleme. Nimm lieber xyz.OT:
Ich will aber! Und ich habe schon ganz tolle andere Sachen gemacht!Forum:
?!Ansonsten kann ich mich Th69 nur anschließen, C++/CLI ist Microsofts misslungener Versuch, GUIs mit .Net Komponenten umsetzen zu wollen. Die .Net Konzepte lassen sich mit C++ nicht umsetzen, da hat MS dann einen eigenen C++ Dialekt erfunden, der eine Brücke zwischen den beiden Welten schlagen soll.
-
@Rikku33 sagte in VC ++ 2008 Kindelemente vom Kindelement vom tableLayoutPanel ansprechen?:
Google empfielt mir für meine Vorhaben immer C++ und da CLI nunmal kein C# ist,
Von KI-Ratschlägen immer Abstand nehmen, die können das noch nicht so gut, und bringen dich dann schnell auf einen Holzweg...
Vereinfacht gesagt, wenn KI merkt, dass du noch nicht so die Ahnung hast, gibt sie auch dumme Ratschläge (und die Masse der Anfänger spielt dabei natürlich auch eine nicht unwesentliche Rolle)... Aber das kann sich alles in Zukunft ändern.
-
@Rikku33 sagte in VC ++ 2008 Kindelemente vom Kindelement vom tableLayoutPanel ansprechen?:
Was habt ihr bloß alle für ein Problem mit Windows Forms?
Mit Windows Forms nicht, sondern dieses mit C++/CLI zu nutzen. Die Hauptsprachen für Windows Forms (und generell .NET) sind nun mal C# und Visual Basic (VB .NET).
Evtl. also mal VB .NET ausprobieren (da du ja anscheinend früher schon mit BASIC programmiert hast), falls dir C# nicht zusagt.Oder meintest du dies mit
Ich hab zwischendurch auch mal dieses neue Basic probiert, ...
?
Und welche .NET-Version verwendest du eigentlich? Bist du wirklich noch mit Windows XP unterwegs und hast die letzten 15 Jahre verschlafen?
PS:
C++/CLI (früher hieß es "Managed C++") ist nur als Interop-Sprache gedacht, um Code zwischen C++ und .NET auszutauschen (also hauptsächlich, um Daten zu transferieren).