|
Bentutzen Sie diese Datenbank und erstellen sie eine Benutzer- oder System-DSN im ODBC Manager in der Systemsteuerung mit dem Namen "splitter". Wie das geht steht hier. ![]() Die Anwendung Splitter soll so verändert werden, dass die vorher in einem geteilten Fenster angezeigten Elemente nun mittels Karteikarten angezeigt werden. |



// MainFrm.cpp : Implementierung der Klasse CMainFrame
//
#include "stdafx.h"
#include "splitter.h"
#include "MainFrm.h"
#include "SplitterDoc.h"
//#include "DKunde.h" gelöscht
//#include "DLand.h" gelöscht
//#include "DJoin.h" gelöscht
//#include "DAdresse.h" gelöscht


// splitter.cpp : Legt das Klassenverhalten für die Anwendung fest.
//
#include "stdafx.h"
#include "splitter.h"
#include "MainFrm.h"
#include "splitterDoc.h"
// Löschen der folgenden Zeile
//#include "DKunde.h"
// Includieren der am Anfang erstellten View
#include "TabView.h"
BOOL CSplitterApp::InitInstance()
{
AfxEnableControlContainer();
// Standardinitialisierung
// Wenn Sie diese Funktionen nicht nutzen und die Größe Ihrer fertigen
// ausführbaren Datei reduzieren wollen, sollten Sie die nachfolgenden
// spezifischen Initialisierungsroutinen, die Sie nicht benötigen, entfernen.
#ifdef _AFXDLL
Enable3dControls(); // Diese Funktion bei Verwendung von MFC in gemeinsam genutzten DLLs aufrufen
#else
Enable3dControlsStatic(); // Diese Funktion bei statischen MFC-Anbindungen aufrufen
#endif
// Ändern des Registrierungsschlüssels, unter dem unsere Einstellungen gespeichert sind.
// ZU ERLEDIGEN: Sie sollten dieser Zeichenfolge einen geeigneten Inhalt geben
// wie z.B. den Namen Ihrer Firma oder Organisation.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Standard INI-Dateioptionen laden (einschließlich MRU)
// Dokumentvorlagen der Anwendung registrieren. Dokumentvorlagen
// dienen als Verbindung zwischen Dokumenten, Rahmenfenstern und Ansichten.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSplitterDoc),
RUNTIME_CLASS(CMainFrame), // Haupt-SDI-Rahmenfenster
RUNTIME_CLASS(CTabView)); // Hier die Anfang erstellte View eintragen.
AddDocTemplate(pDocTemplate);
// Befehlszeile parsen, um zu prüfen auf Standard-Umgebungsbefehle DDE, Datei offen
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Verteilung der in der Befehlszeile angegebenen Befehle
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// Das einzige Fenster ist initialisiert und kann jetzt angezeigt und aktualisiert werden.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}


void CTabView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
// Jeweils anlegen des Speichers für den Dialog
// und anlegen der dahinterliegenden Windows Datenstruktur mit Create
dialoge[0] = new DiaAdresse();
dialoge[0]->Create(IDD_ADRESSE,&m_tabctrl);
m_tabctrl.InsertItem(0,"Adresse");
dialoge[1] = new DiaJoin();
dialoge[1]->Create(IDD_JOIN,&m_tabctrl);
m_tabctrl.InsertItem(1,"Join");
dialoge[2] = new DiaKunde();
dialoge[2]->Create(IDD_KUNDE,&m_tabctrl);
m_tabctrl.InsertItem(2,"Kunde");
dialoge[3] = new DiaLand();
dialoge[3]->Create(IDD_LAND,&m_tabctrl);
m_tabctrl.InsertItem(3,"Land");
}
void CTabView::OnSize(UINT nType, int cx, int cy)
{
CFormView::OnSize(nType, cx, cy);
// Wenn die Fenstergröße verändert wird, das CTabCtrl anpassen
if (m_tabctrl.GetSafeHwnd() != NULL)
m_tabctrl.MoveWindow(0,0,cx,cy);
CRect rechteck;
// Ebenso den angezeigten Dialog anpassen
// Nur wenn CTabCtrl schon oder noch existiert.
if (m_tabctrl.GetSafeHwnd() != NULL)
{
// Größe des CTabCtrls holen
m_tabctrl.GetClientRect(rechteck);
// Dialog an die Größe des Fensters anpassen und anzeigen
dialoge[0]->SetWindowPos(NULL,rechteck.left+5,rechteck.top+25,
rechteck.right-10,rechteck.bottom-30,SWP_SHOWWINDOW);
}
}
void CTabView::OnSelchangingTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
int alt;
// Nummer der alten aktivierten Registerkarte holen
alt = m_tabctrl.GetCurSel();
// und verstecken
dialoge[alt]->ShowWindow(SW_HIDE);
*pResult = 0;
}
void CTabView::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
int neu;
CRect rechteck;
// Nummer der neuen aktivierten Registerkarte holen
neu = m_tabctrl.GetCurSel();
// Holen der aktellen Größe des Fensters
GetClientRect(rechteck);
m_tabctrl.GetClientRect(rechteck);
// Dialog an die Größe des Fensters anpassen und anzeigen
dialoge[neu]->SetWindowPos(NULL,rechteck.left+5,rechteck.top+25,
rechteck.right-10,rechteck.bottom-30,SWP_SHOWWINDOW);
*pResult = 0;
}
#include "RAdresse.h"
class DiaAdresse : public CDialog
{
// etc...
BOOL DiaAdresse::OnInitDialog()
{
CDialog::OnInitDialog();
rec.Open();
Update(true);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurückgeben
}
void DiaAdresse::Update(bool db_to_ctrl)
{
if (db_to_ctrl)
{
// von der DB in die Eingabefelder
m_hausnr = rec.m_Hausnummer;
m_id = rec.m_Index;
m_land = rec.m_Land;
m_ort = rec.m_Ort;
m_plz = rec.m_Postleitzahl;
m_strasse = rec.m_Strasse;
UpdateData(false);
}else
{
// von den Eingabefeldern in die DB
UpdateData(true);
rec.m_Hausnummer = m_hausnr;
// Die ID wird von der Datenbank automatisch vergeben
// desshalb nicht setzen
// rec.m_Index = m_id;
rec.m_Land = m_land;
rec.m_Ort = m_ort;
rec.m_Postleitzahl = m_plz;
rec.m_Strasse = m_strasse;
}
}
void DiaAdresse::OnAdd()
{
// DB für neuen Datensatz vorbereiten
rec.AddNew();
// Werte in den Eingabefeldern in die Variablen kopieren
Update(false);
// Einfügevorgang abschließen
rec.Update();
// Datensätze neu selektieren
// wenn man dies nicht tut, wird der eingefügte Datensatz nicht angezeigt
rec.Requery();
// Den aktuellen Datensatz in die Eingabefelder kopieren
Update(true);
}
void DiaAdresse::OnDel()
{
// Den aktuellen Datensatz löschen
rec.Delete();
// Datensätze neu selektieren
// Gelöschter Datensatz wird sonst noch angezeigt
rec.Requery();
// Den aktuellen Datensatz in die Eingabefelder kopieren
Update(true);
}
void DiaAdresse::OnUpdate()
{
// Den aktuellen Datensatz zum ändern vorbereiten
rec.Edit();
// Den aktuellen Datensatz mit den Werten
// in den Eingabefeldern überschreiben
Update(false);
// Updatevorgang abschließen
rec.Update();
}
void DiaAdresse::OnVor()
{
// Datensatzzeiger um eins vorbewegen
rec.MoveNext();
// wenn er nun nach dem letzten Datensatz steht
// wieder rückgängig machen
if (rec.IsEOF())
rec.MovePrev();
// Aktuellen Datensatz in die Eingabefelder kopieren
Update(true);
}
void DiaAdresse::OnZurueck()
{
// Datensatzzeiger um eins zurück bewegen
rec.MovePrev();
// wenn er nun vor dem ersten Datensatz steht
// wieder rückgängig machen
if (rec.IsBOF())
rec.MoveNext();
// Aktuellen Datensatz in die Eingabefelder kopieren
Update(true);
}
BOOL DiaJoin::OnInitDialog()
{
CDialog::OnInitDialog();
rec.Open();
// Tabellenüberschriften setzen
m_list.InsertColumn(0,"Kunde",LVCFMT_LEFT,60);
m_list.InsertColumn(1,"Ort",LVCFMT_LEFT,60);
m_list.InsertColumn(2,"Strasse",LVCFMT_LEFT,80);
m_list.InsertColumn(3,"Hausnr",LVCFMT_LEFT,40);
m_list.InsertColumn(4,"Land",LVCFMT_LEFT,80);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurückgeben
}
Methode für den Button:
void DiaJoin::OnSuch()
{
// Natural Join (jedes mit jedem) verhindern
rec.m_strFilter = "Kunde.Adresse = Adresse.Index AND Adresse.Land = Land.Index";
// Schauen, ob etwas im Eingabefeld steht
UpdateData();
if (m_kunde != "")
//Wenn ja, danach suchen
rec.m_strFilter += " AND Kunde.Name = '"+m_kunde+"'";
// Recordset aktualisieren ( Suchregel wird angewendet )
rec.Requery();
// Alte Items der CListCtrl löschen
m_list.DeleteAllItems();
// Solange Elemente vorhanden
while (!rec.IsEOF())
{
// in CListCtrl einfügen
int item = m_list.InsertItem(0,rec.m_kunde,-1);
m_list.SetItemText(item,1,rec.m_ort);
m_list.SetItemText(item,2,rec.m_strasse);
m_list.SetItemText(item,3,rec.m_hausnummer);
m_list.SetItemText(item,4,rec.m_land);
// Aktellen Datensatz um eins weitersetzen
rec.MoveNext();
}
}
BOOL CSplitterApp::PreTranslateMessage(MSG* pMsg)
{
// Tastendrücke abfangen
if (pMsg->message == WM_KEYDOWN)
{
// Die View holen
CTabView* view = (CTabView*)((CFrameWnd*)AfxGetMainWnd())->GetActiveView();
// Tastendruck an die Behandlungsfunktion der eigenen View weiterleiten
if (view->BehandleTastenDruck(pMsg))
// Taste behandelt wurde sofort zurückkehren
return TRUE;
}
// Sonst Standardbehandlung durchführen
return CWinApp::PreTranslateMessage(pMsg);
}
Und hier nun selbst erstellte Methode der Klasse CTabView, an die die Nachrichten weitergeleitet werden:
bool CTabView::BehandleTastenDruck(MSG *pMsg)
{
// Wenn die Tasten STRG und TAB gleichzeitig gedrückt werden
if ((pMsg->wParam == VK_TAB) && (GetKeyState(VK_CONTROL) < 0))
{
int alt = m_tabctrl.GetCurSel();
int neu;
// Wenn die Shifttaste gedrückt wird
if (GetKeyState(VK_SHIFT) < 0)
// eins abziehen
// mathematischer Trick
neu = (m_tabctrl.GetCurSel()-1+4)%4;
else
// sonst eins dazuzählen
neu = (m_tabctrl.GetCurSel()+1)%4;
// Nächsten Reiterbutton aktivieren
m_tabctrl.SetCurSel(neu);
// Alten Dialog verstecken
dialoge[alt]->ShowWindow(SW_HIDE);
// Neuen anzeigen
CRect rechteck;
// Holen der aktellen Größe des Fensters
m_tabctrl.GetClientRect(rechteck);
// Dialog an die Größe des Fensters anpassen und anzeigen
dialoge[neu]->SetWindowPos(NULL,rechteck.left+5,rechteck.top+25,rechteck.right-10,rechteck.bottom-30,SWP_SHOWWINDOW);
}
// Dialoge werden normalerweise bei ESC und ENTER geschlossen und zerstört
// um dies zu verhindern leiten wir die Taste einfach nicht weiter
if ((pMsg->wParam == VK_RETURN) || (pMsg->wParam == VK_ESCAPE))
return true;
return false;
}