Probleme mit Grafik
-
Habe folgendes Problem, versuche in ein PictureControl zu zeichnen, dessen Handle ich vorher mit
CWnd* hWndGraphArea = GetDlgItem(IDC_GRPH_AREA_ONE);
ermittelt habe. Nun rufe ich DrawChart auf:
m_pLeftGraph->DrawChart(m_pLeftFile, hWndGraphArea);
und ein zu zeichnender Datensatz und das Handle auf den Zeichenbereich werden übergeben.
void CGraphics::DrawChart(CDataSet* myDataSet, CWnd* myGraphHandle) { int x1, x2, y1, y2; // Initialisierung CClientDC dc(myGraphHandle); LPRECT PaintRect = new RECT; myGraphHandle->GetClientRect(PaintRect); CPen penBlack(PS_SOLID, 1, RGB(0,0,0)); x1 = PaintRect->left; y1 = PaintRect->top; x2 = PaintRect->right; y2 = PaintRect->bottom; ... }
Problem ist, wie kann ich verifizieren, ob bei der Initialisierung des Zeichnens alles klar geht? Die Zeile myGraphHandle->GetClient... sollte die RECT-Struktur füllen, tut sie aber nicht. Kommt aber auch keine Fehlermeldung? Wie gehe ich hier vor?
Wie finde ich die Ursache?
-
Hi,
GetClientRect liefert keine Vernünftigen Daten? Es kann sein, das dein Handle
auf das Window-Objekt nicht mehr gültig ist, den GetDlgItem liefert unter
Umständen nur ein temporäres Handle zurück, und kann nur innerhalb
der Funktion verwendet werden.MSDN:
Return Value
Returns a pointer to the given control or child window. If no control with the integer ID given by the nID parameter exists, the value is NULL.The returned pointer may be temporary and should not be stored for later use.
Kannst Du der Zeichenfunktion nicht die ID des Controls übergeben und
erst in der Zeichenfunktion GetDlgItem aufrufen?
Dann sollte GetClientRect die richtigen Werte liefern.BTW würde ich die RECT Struktur nicht per new anlegen (Heapfragmentation und
Gefahr von Speicherleck).
Lieber:CClientDC dc(myGraphHandle); RECT PaintRect; myGraphHandle->GetClientRect(&PaintRect);
Gruss
EB
-
Danke, das mit dem RECT funktioniert schon mal...
Leider habe ich mich nicht genau ausgedrückt. Die Klasse, in der GetDlgItem(nID) aufgerufen wird, ist die Dlg-Applikatonsklasse. Dort funktioniert es ohne zu murren. In der CGraphics-Klasse sagt er immer
GetDlgItem : Funktion akzeptiert keine 1 Argumente
warum auch immer. Wie kann ich ihm klar machen, welche GetDlgItem() es ist?
-
Hi,
deine CGraphícs-Klasse ist also unabhängig vom Dialog. CGraphics verwendet
dann GetDlgItem aus der WINAPI und benötigt daher ein Handle auf ein
Fenster (CDialog in deinem Fall). An das Handle kannst Du auf verschiedene
Arten kommen. Wenn es dann Fehlerfrei kompiliert, bezweifle ich jedoch,
das deine Zeichenroutine funktioniert. Bzw. sie wird zwar ausgeführt, jedoch
siehst Du sehr wahrscheinlich nichts, da das PictureControl deine Aktion
wieder überzeichnet.Ich würde das Programmdesign nochmal überlegen.
Mein Vorschlag: Du leitest eine Klasse vom PictureControl, welches ja nur ein
CStatic ist ab, und überschreibst dann die OnPaint-Methode um deine Daten zu
zeichnen. Du setzt ein Picture-Control im Editor auf deinen Dialog, gibst dem
eine ID z.B. IDC_CHARTCTRL und erstellst eine Membervariable dafür.
Dann änderst Du den Datentyp der Membervariable in deine Klasse um.Ein Beispiel habe ich mal angeheftet:
// ChartDlg.h : Headerdatei // #pragma once #include "afxwin.h" #include <afxtempl.h> // benötigt für CArray // CChartcontrol class CChartControl : public CStatic { public: DECLARE_MESSAGE_MAP() afx_msg void OnPaint(); }; // CChartDlg Dialogfeld class CChartDlg : public CDialog { // Konstruktion public: CChartDlg(CWnd* pParent = NULL); // Standardkonstruktor // Dialogfelddaten enum { IDD = IDD_CHART_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV-Unterstützung // Implementierung protected: HICON m_hIcon; // Generierte Funktionen für die Meldungstabellen virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: CChartControl m_wndChartCtrl; CArray<UINT, UINT> m_arrData; // array für ein paar Daten };
// ChartDlg.cpp : Implementierungsdatei // #include "stdafx.h" #include "Chart.h" #include "ChartDlg.h" #include ".\chartdlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CChartDlg Dialogfeld CChartDlg::CChartDlg(CWnd* pParent /*=NULL*/) : CDialog(CChartDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CChartDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_CHARTCTRL, m_wndChartCtrl); } BEGIN_MESSAGE_MAP(CChartDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP END_MESSAGE_MAP() // CChartDlg Meldungshandler BOOL CChartDlg::OnInitDialog() { CDialog::OnInitDialog(); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE); // fülle array mit ein paar Daten in Prozent für Säulendiagramm m_arrData.Add(30); m_arrData.Add(40); m_arrData.Add(60); m_arrData.Add(80); m_arrData.Add(90); return TRUE; } void CChartDlg::OnSysCommand(UINT nID, LPARAM lParam) { CDialog::OnSysCommand(nID, lParam); } void CChartDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } HCURSOR CChartDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } // CChartControl BEGIN_MESSAGE_MAP(CChartControl, CStatic) ON_WM_PAINT() END_MESSAGE_MAP() void CChartControl::OnPaint() { CPaintDC dc(this); CRect rcClient; GetClientRect(&rcClient); // zeichne einen Rahmen dc.Rectangle(&rcClient); rcClient.DeflateRect(1, 1); // zeichne Hintergrund weiss dc.FillSolidRect(&rcClient, RGB(255, 255, 255)); rcClient.DeflateRect(1, 1); // hole zeiger auf Dialogklasse CChartDlg* pDialog = DYNAMIC_DOWNCAST(CChartDlg, GetParent()); if ( pDialog ) // zeiger erhalten? { // zeichne Säulendiagramm int x = rcClient.Width() / pDialog->m_arrData.GetCount(); for ( int i = 0; i < pDialog->m_arrData.GetCount(); ++i ) { int y = rcClient.Height() * pDialog->m_arrData.GetAt(i) / 100; dc.FillSolidRect(rcClient.left + i * x, rcClient.bottom, x, -y, RGB(255, 0, 0)); } } }
Gruss
EB
-
Super,
das hat schon mal funktioniert. Verstehe jetzt nur nicht, warum ich zwar die Charts sehe, aber wenn ich statt dessenfor (int i = 0; i < rcClient.right; ++i) { dc.MoveTo(i,100); dc.LineTo(i,100); }
an die Stelle unter
// zeichne Säulendiagramm
schreibe, sehe ich nix...
Stift wurde mit
CPen penRed(PS_SOLID, 1, RGB(255,0,0)); dc.SelectObject(&penRed);
initialisiert...
-
Hi,
du zeichnest ja auch nichts!
for (int i = 0; i < rcClient.right; ++i) { dc.MoveTo(i,100); dc.LineTo(i,100); }
setz mal Zahlen für i ein:
MoveTo(0, 100) -> LineTo(0, 100) = NICHTSfor (int i = 0; i < rcClient.right; ++i) { dc.MoveTo(i,100); dc.LineTo(i,150); }
MoveTo(0, 100) -> LineTo(0, 150) = 50px Y-Linie
Gruss
EB
-
Ok, gegen dieses Argument hab ich keine Chance... Asche auf mein Haupt!
Danke, es geht. Vielen Dank!PS: Ich war immer der Meinung eine Linie von x,y bis x,y ist ein Pixel an dieser Stelle. Gibt es in der CDC-Klasse auch Pixelfunktionen? Muss nämlich Kurven zeichnen.