Hi,
den Parent zu speichern macht wenig Sinn. Jedesmal, wenn du die Komponenten lädst, ist der Parent ja ein anderer.
Ausserdem ist der Parent auch nur ein Objekt. Du erntest dadurch nur Zugriffsverletztungen oder Meldungen wie "Objekt hat kein übergeordnetes Fenster".
Du köntest allerding hingehen und das Parent- Objekt speichern anstatt die Unterkomponenten.
So sieht eine gespeicherte Datei aus, in der ein Formular gespeichert wurde:
//..................................................
object Form1: TForm1
Left = 192
Top = 107
Width = 696
Height = 480
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
end
Ja, also exact so wie eine Fromulardatei. Um nun die Variablen deiner Klassen beim Speichervorgang mit zu berücksichtigen müssen diese als __properties unter __published deklariert sein. Ausserdem muss deine Klasse(n) zumindest von TPresistent abgeleitet sein. Dort werden die Methoden für das schreiben von Komponentenn implementiert.
Wenn du andere Klassen innerhalb deiner Klasse verwendest, so müssen deren Eigenschaften natürlich auch __propierty's sein.
Im Normalfall werden diese aber nicht mitgespeichert. Um dieses zu ändern gibt es mehrere Möglichkeiten:
1. du überschreibst die Methode DefineProperties und erstellst Wrieter und Reader-Methoden, die die Unterklassen in der Verschachtelungstiefe abspeichern.
Ist allerdings Zeitraubend.
2. Du definierts die unterklassen als SubKomponenten :
FDataSource=new TDataSource(this);
FDataSource->Name="DataSource";
FDataSource->SetSubComponent(this);
So gehst du durch die Verschachtellungstiefe. Jede Klasse die eine Unterklasse besitzt passt du so an. In der Owner- Klasse werden alle Properties gespeichert.
3. Du definierst die Unterklassen als Eigenschaft selbst und schriebst eigene Property-Editoren, die das setzen der Klasseninstanzen durchführen und das speichern der SubKlassen übernimmt.
Hierzu leitest du eine Klasse von TPropertyEditor ab.
Die einfachere Lösung wäre wohl Lösung 2.
[ Dieser Beitrag wurde am 02.08.2002 um 15:34 Uhr von AndreasW editiert. ]
<edit>Das Problem mit den Code-Tags behoben</edit>
[ Dieser Beitrag wurde am 02.08.2002 um 17:18 Uhr von junix editiert. ]
Original erstellt von cppnewbie:
erstmal danke für die schnelle hilfe wenn es möglich ist, den screenshot direkt zu speichern, ohne ihn erst in ein timage zu laden, dann wäre das natürlich noch besser.
Erstelle vor der Funktion eine Instanz von TBitmap. Wenn du dir die Methoden von TBitmap anschaust, wirst du auch eine finden, die dich das Ganze dann speicher lässt.
delete nicht vergessen am ende der Funktion! (:
-junix
Ein Beispiel für den Zugriff auf Variablen über Properties.
// Unit1.h
private:
int Zaehler;
// Unit2.h
private:
int fZaehler;
protected:
void __fastcall SetZaehler(int);
public:
__property int Zaehler = {read = fZaehler , write = SetZaehler};
// Irgendwo in Unit1.cpp
// (nicht vergessen, Unit2.h mit einzubinden)
Form2->Zaehler = Zaehler;
Form2->Show();
// Unit2.cpp
void __fastcall TForm2::SetZaehler(int zaehler)
{
fZaehler = zaehler;
// und möglicherweise noch anderes Zeugs
}
[ Dieser Beitrag wurde am 14.05.2002 um 22:30 Uhr von junix editiert. ]
Es war ein mal ein... ne nicht ein Prinz, sonder ein Problem
- BCB5 Projekte mit BCB6 bearbeiten:
Ich hatte anfangs Probleme beim Import von BCB5-Projekten, BCB6 stürzte immer ab, wenn ich versuchte das Projekt zu schließen. Die Ursache lag an den "doppelten Reiter im Editorfenster": er zeigte in oberen Reiter die beiden Dateien *.cpp und *.h und unten noch mal. Und das brachte ihn durcheinander....
Lösung:
In BCB5 Projekt öffnen und dann alle Quelltexte im Editor schliessen. Projekt schließen. Dabei wird in der Projekt-Datei dieser Zustand (keine offenen Quelldateien) abgespeichert. Jetzt in BCB6 Projekt öffnen. Es wird Projekt geöffnet, aber ohne die Quellen. Jtzt kann man die Quelldateien nacheinander sauber öffnen (*.cpp (nur *.cpp)wird in den Reiter oben angezeigt und *.cpp und *.h unten).
oder einfacher:
in BCB6 BCB5-Projekt öffnen und dann alle oben angezeigten *.h schliessen. **!!! .h, nicht .cpp !!! Dannach kann man auch das Projekt schliessen.
[ Dieser Beitrag wurde am 08.05.2002 um 10:23 Uhr von Xqgene editiert. ]
also einfacher gehts auf alle fälle so...
void __fastcall TForm1::OpenDialog1Show(TObject *Sender)
{
// der Öffnen-Knopf hat die Kennung eines Okay-Buttons
HWND hDialog = GetParent(OpenDialog1->Handle);
HWND button = GetDlgItem(hDialog, ID_OK); //ok-button
// den text setzen (nach gutdünken)
SetWindowText(button, "Löschen");
}
okay... nicht einfacher, aber genauer...
[ Dieser Beitrag wurde am 06.05.2002 um 20:38 Uhr von Jansen editiert. ]
In diesem Zusammenhang ist auch diesem beitrag Beachtung zu schenken: Tasten - systemweit abfangen (Hooks)
Es gibt aber auch eine Lösung mit RegisterHotKey:
Zunächst schreibst du beim OnCreate Event des betroffenen Formulars folgendes:
HotKeyIdentifier_uint = GlobalAddAtom("F3-Hotkey");
HotKeyModifier_uint = 0;
RegisterHotKey(Handle, HotKeyIdentifier_uint, HotKeyModifier_uint, VK_F3); //Hotkey registrieren.
Das registriert den Hotkey Systemweit.
In den OnDestroy Event schreibst du folgendes rein:
UnregisterHotKey(Handle, HotKeyIdentifier_uint); //HotKey löschen
GlobalDeleteAtom(HotKeyIdentifier_uint); //HotKey Identifier löschen
Das löscht den Hotkey wieder aus dem System.
In den Private-Teil der Formularklasse schreibst du:
/* Eine eindeutige ID für den Hotkey suchen. Der String ist egal. *
* Sinnvollerweise beschreibend zum Hotkey. Diese ID wird auch benötigt, wenn *
* man den Hotkey zerstören will. Daher sollte der Wert irgendwo in der Klasse*
* welche den HotKey verwaltet gespeichert werden. */
unsigned int HotKeyIdentifier_uint;
/* Die Modifier sind die Tasten welche zusätzlich auch noch gedrückt werden *
* müssen. Also z.B. Control oder so. Hier ist es keine (0). Um genauere *
* Info zu erhalten musst du einfach in der Hilfe unter "RegisterHotKey" nach *
* lesen. (Windows SDK Hilfe) */
unsigned int HotKeyModifier_uint;
/* Funktionsdeklaration des Message-Handlers */
void __fastcall WMHotKey(TMessage &Msg);
Ans Ende des Public-Teils der Formularklasse fügst du das hier an:
/* MessageMap, damit das Form auch weiss, wo die Message hin geschickt werden soll */
BEGIN_MESSAGE_MAP
/* MESSAGE_HANDLER(<Nachrichtenname>, <Nachrichtentyp>, <Handler-Funktionssname> */
MESSAGE_HANDLER(WM_HOTKEY, TMessage, WMHotKey)
END_MESSAGE_MAP(TForm)
In die Implementierungsdatei gehört dann die Implementierung des Message-Handlers.
//---------------------------------------------------------------------------
void __fastcall TForm1::WMHotKey(TMessage &Msg)
{
TForm::Dispatch(&Msg);
//--TODO: Gewünschten Code einfügen
}
//---------------------------------------------------------------------------
Und fertig ist das Wunderding.
-junix
[ Dieser Beitrag wurde am 22.01.2003 um 15:01 Uhr von junix editiert. ]
Übersetzung gemäss diesem Artikel:
Angenommen du möchtest Form1 Drag n Drop fähig machen:
Füge beim OnCreateEvent von Form1 folgendes hinzu:
// Sorgt dafür, dass dein Formular DnD akzeptiert
DragAcceptFiles(Form1->Handle,true);
Jetzt schreibst du in die Private-Deklaration von TForm1
// Deklaration des MessageHandlers
void __fastcall WmDropFiles(TWMDropFiles& Message);
Schreib das ans Ende deiner public-Sektion des TForm1 headers:
// Sets up the message handler
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_DROPFILES,TWMDropFiles,WmDropFiles)
END_MESSAGE_MAP(TForm)
Jetzt die Implementierung. Schreib das in deine Form1.cpp
[cpp]// Implementierung des Message Handlers
void __fastcall TForm1::WmDropFiles(TWMDropFiles& Message)
{
char buff[MAX_PATH];
HDROP hDrop = (HDROP)Message.Drop;
int numFiles = DragQueryFile(hDrop,-1, NULL, NULL);
for (int i=0;i<numFiles;i++)
{
DragQueryFile(hDrop, i, buff, sizeof(buff));
// **HIER kannst du jede "gedropte" Datei mit
**// einem eigenen Algorithmus verarbeiten. Zum Beispiel
// die Dateien öffnen oder die Namen mal vormerken.
}
DragFinish(hDrop);
}[/cpp]
Zur Krönung schreibst du jetzt noch oben in die .cpp folgendes:
#include <shellapi.h> //Brauchst du damit "DragAcceptFiles" & Co erkannt werden.
Et Voilà (: Habs ausprobiert, klappt einwandfrei bei mir. Hoffe bei dir auch.
-junix
[ Dieser Beitrag wurde am 12.05.2002 um 16:03 Uhr von junix editiert. ]
[ Dieser Beitrag wurde am 19.06.2003 um 09:33 Uhr von Jansen editiert. ]
Hey, die Idee mit dem CommaText finde ich ja mal voll geil. Kann man dann auf jedes StringGrid anwenden ohne sich um die Anzahl Cols scheren zu müssen. ***top***
Schreib dir eine eigene Verzögerungs-Routine:
void delay(int D) // Dauer in Millisekunden
{
for (int i = 0; i < D; i += 50)
{
Sleep(50);
Application->ProcessMessages();
}
}
Mit ProcessMessages wird vermieden, dass das Programm "abgestürzt" aussieht.