Cursor mit gedrückter linker Maustaste in x-Richtung verschieben

Cappaja

Erfahrenes Mitglied
hallo,

ich mal wieder ;)
nachdem das mit dem cursor setzen wunderbar funktioniert möchte ich nun gerne die möglichkeit haben, den gesetzten cursor durch gedrückt halten der linken maustaste in x-Richtung zu verschieben. momentan benutze ich LButtonDown() um den cusor zu setzen, ich geh mal davon aus das ich ihn über eine taste oder einen button setzen sollte damit ich den gesetzten cursor mit gedrückter linker maustaste verschieben kann.

soweit so gut, was ich wissen möchte ist nur eine ungefähre vorgehensweise, da ich so etwas noch nie versucht habe. WM_MOUSEMOVE wird ja aufgerufen sobald die maus bewegt wird, als konstante kann man ja MK_LBUTTON anstelle des nFlags übergeben. sollte ich dann WM_MOUSEMOVE innerhalb der LButtonDown() methode verarbeiten oder sollte ich einen völlig anderen weg einschlagen?

vielleicht hatte ja jemand schon ein ähnliches problem, ich wäre über ein paar anmerkungen sehr dankbar!
 

Endurion

Erfahrenes Mitglied
Bitte beschreibe genauer, was du vorhast. Von was möchtest du den Cursor verschieben? (bzw. es klingt so, als würdest du versuchen, in einer Edit aus einem anderen Programm einen Text zu selektieren)
 

Cappaja

Erfahrenes Mitglied
oh sorry wenn das so falsch verstanden wurde.

ich meinte nicht den mauscursor (caret) sondern einen cursor in form einer großen vertikalen linie welche mir die x-Pos in einem kartesischen koordinatensystem zurück gibt. die linie setze ich bislang noch über die LButtonDown() message, also mit einem linksklick. beim zweiten linksklick erscheint ein zweiter cursor um das delta zwischen den cursorn zu berechnen, beim ersten rechtsklick wird der zweite cursor gelöscht, beim zweiten rechtsklick der erste cursor gelöscht. dieses spiel lässt sich natürlich beliebig fortsetzen.

jetzt will ich es aber so haben, das sich die beiden cursor in x-richtung verschieben lassen um beispielsweise ein maximalwert genauer anfahren zu können. da ich momentan WM_LBUTTONDOWN und WM_RBUTTONDOWN für das setzen und löschen der beiden cursor benötige, dachte ich das bewegen mittels WM_MOUSEMOVE und den nachrichten WM_LBUTTONUP und WM_RBUTTONUP irgendwie zu realisieren. dafür wollte ich nur eine ungefähre beschreibung wie ich damit vorgehen könnte.

das hauptproblem sehe ich eben darin, dass beim verschieben des cursors ständig neu gezeichnet werden muss. genau für dieses problem suche eine möglichst effiziente methode. da ich das zuvor noch nie gemacht habe, wende ich mich erstmal an euch die schon länger damit arbeiten wie ich.

hier der code welcher für das zeichnen der cursor, sowie das setzen und löschen verantwortlich ist:
(im konstruktor wird das array zu beginn auf {-1, -1} gesetzt, da ich den cursor links neben das hauptfenster setze)

Code:
void CGraph::DrawVCursor(int *pArrayX)
{
	try
	{
		if(!m_pWnd)
		{
			return;
		}

		CPen  *pStandardPen;
		CPen  MyPen;
		CRect DataArea = CalcDataArea();

		// DC zum Zeichnen anlegen
		CDC *pDC = m_pWnd->GetDC();
		MyPen.CreatePen(PS_SOLID, 1, RGB(255,255,255));
		// MyPen als Standard Pen an pDC übergeben
		pStandardPen = pDC->SelectObject(&MyPen);

		// ### TODO Zeichenroutine für Cursor ###
		pArrayX = m_arrayX;  // Pointer zeigt auf Startadresse
		pDC->MoveTo(pArrayX[0], DataArea.top);
		pDC->LineTo(pArrayX[0], DataArea.bottom);
		pDC->MoveTo(pArrayX[1], DataArea.top);
		pDC->LineTo(pArrayX[1], DataArea.bottom);

		// CleanUp
		m_pWnd->ReleaseDC(pDC);
	}
    catch(CResourceException &CEx)
    {
        char msg[128];
        CEx.GetErrorMessage(msg, sizeof(msg));
        MessageBox(NULL, msg, "Fehler", MB_ICONERROR);
    }
}

Code:
void CWiwoDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CRect rect = m_pGraph->CalcDataArea();
	BOOL bFlag = CheckRect(point, rect);

	if(bFlag == TRUE)
	{
		int nCX, nCY;
		nCX = point.x;
		nCY = point.y;
		CString sCX, sCY;
		sCX.Format("%d", nCX);
		sCY.Format("%d", nCY);
		m_ctrlCX.SetWindowText(sCX);
		m_ctrlCY.SetWindowText(sCY);
		
		// Zweiter Cursor zeichnen
		if(m_pGraph->m_arrayX[0] != -1 && m_pGraph->m_arrayX[1] == -1)
		{
			m_pGraph->m_arrayX[1] = nCX;
			m_pGraph->DrawVCursor(m_pGraph->m_arrayX);
		}

		// Erster Cursor zeichnen
		if(m_pGraph->m_arrayX[0] == -1)
		{
			m_pGraph->m_arrayX[0] = nCX;
			m_pGraph->DrawVCursor(m_pGraph->m_arrayX);
		}
	}
	else
		TRACE("\nCX und CY liegen ausserhalb!\n");
	
	CDialog::OnLButtonDown(nFlags, point);
}

void CWiwoDlg::OnRButtonDown(UINT nFlags, CPoint point) 
{
	CRect rect = m_pGraph->CalcDataArea();
	BOOL bFlag = CheckRect(point, rect);

	if(bFlag == TRUE)
	{
		int nCX, nCY;
		nCX = point.x;
		nCY = point.y;
		CString sCX, sCY;
		sCX.Format("%d", nCX);
		sCY.Format("%d", nCY);
		m_ctrlCX.SetWindowText(sCX);
		m_ctrlCY.SetWindowText(sCY);

		// Erster Cursor löschen
		if(m_pGraph->m_arrayX[1] == -1 && m_pGraph->m_arrayX[0] != -1)
		{
			m_pGraph->m_arrayX[0] = -1;
			m_pGraph->PaintGraph();
		}

		// Zweiter Cursor löschen
		if(m_pGraph->m_arrayX[1] != -1 && m_pGraph->m_arrayX[0] != -1)
		{
			m_pGraph->m_arrayX[1] = -1;
			m_pGraph->PaintGraph();
		}
	}
	else
		TRACE("\nCX und CY liegen ausserhalb!\n");
	
	CDialog::OnRButtonDown(nFlags, point);
}
 
Zuletzt bearbeitet:

Endurion

Erfahrenes Mitglied
Da kommt man um Neuzeichnen nicht drumrum. Aber man muss ja nicht alles neuzeichnen!

1)
Keinen Zeichencode ausserhalb WM_PAINT. Ist zwar lästig, aber besser ein Flag setzen, dass nur der Cursor geupdated werden soll. Und dann kein volles InvalidateRect, sondern nur die betroffenen Ausschnitte

2)
Wenn das Cursor-Flag gesetzt ist, nur die betroffenen Rects neu darstellen, der Rest bleibt wie er ist.

Das ist nervige Frickelarbeit, aber damit bist du am schnellsten.
 

Cappaja

Erfahrenes Mitglied
hi endurion,

ich habe vorerst die beiden WM_MESSAGE funktionen für links und rechtsklick wie folgt modifiziert: bevor der cursor gesetzt wird, speichere ich den ausschnitt wo der cursor gezeichnet wird in ein CRECT (m_savePlaceHolder1 und 2 für die beiden Cursor). Beim löschen der Cursor rufe ich dann via InvalidateRect die zuvor abgespeicherten Platzhalter auf, welche neu gezeichnet werden sollen.

Mein Problem: ich kann problemlos die cursor setzen, beim löschen werden sie jedoch nicht auf den ersten blick gelöscht, sondern erst wenn man das fenster beispielsweise über den bildschirmrand hinaus- und wieder herein zieht, was doch eigentlich wiederum ein WM_PAINT auslöst. Ich bin mit dem Debugger durch und in meinen Platzhaltern für die RECTS stehen die korrekten Werte darin. Was mache ich noch falsch? Ist es überhaupt möglich ein RECT der breite 1 abzuspeichern? habe für left und right logischerweise den gleichen wert für die x-koordinate drinstehen.

EDIT: Problem gelöst! die breite war das problem, ich habe einfach die x-koordinate mit +1 weitergegeben und es ging, für -1 nach links erzielt man komischerweise denselben erfolg.

Code:
void CWiwoDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CRect rect = m_pGraph->CalcDataArea();
	BOOL bFlag = CheckRect(point, rect);

	if(bFlag == TRUE)
	{	
		int nCX = point.x;

		// Zweiter Cursor zeichnen
		if(m_pGraph->m_arrayX[0] != -1 && m_pGraph->m_arrayX[1] == -1)
		{
			m_pGraph->m_arrayX[1] = nCX;

			// Platzhalter2 vor Zeichenroutine abspeichern
			m_savePlaceHolder2.bottom = rect.bottom;
			m_savePlaceHolder2.top    = rect.top;	
			m_savePlaceHolder2.right  = nCX+1;
			m_savePlaceHolder2.left   = nCX;

			m_pGraph->DrawVCursor(m_pGraph->m_arrayX);
			CString sCX2;
			sCX2.Format("%d", nCX);
			m_ctrlCX2.SetWindowText(sCX2);
		}
		
		CursorDelta();

		// Erster Cursor zeichnen
		if(m_pGraph->m_arrayX[0] == -1)
		{
			m_pGraph->m_arrayX[0] = nCX;

			// Platzhalter1 vor Zeichenroutine abspeichern
			m_savePlaceHolder1.bottom = rect.bottom;
			m_savePlaceHolder1.top    = rect.top;	
			m_savePlaceHolder1.right  = nCX+1;
			m_savePlaceHolder1.left   = nCX;
			
			m_pGraph->DrawVCursor(m_pGraph->m_arrayX);
			CString sCX1;
			sCX1.Format("%d", nCX);
			m_ctrlCX1.SetWindowText(sCX1);
		}
	}
	else
		TRACE("\nCX und CY liegen ausserhalb!\n");
	
	CDialog::OnLButtonDown(nFlags, point);
}

void CWiwoDlg::OnRButtonDown(UINT nFlags, CPoint point) 
{
	CRect rect = m_pGraph->CalcDataArea();
	BOOL bFlag = CheckRect(point, rect);

	if(bFlag == TRUE)
	{
		// Erster Cursor löschen
		if(m_pGraph->m_arrayX[1] == -1 && m_pGraph->m_arrayX[0] != -1)
		{
			m_pGraph->m_arrayX[0] = -1;
			//m_pGraph->PaintGraph();
			InvalidateRect(&m_savePlaceHolder1, TRUE);
			m_ctrlCX1.SetWindowText("");
			m_ctrlDif.SetWindowText("");
		}

		// Zweiter Cursor löschen
		if(m_pGraph->m_arrayX[1] != -1 && m_pGraph->m_arrayX[0] != -1)
		{
			m_pGraph->m_arrayX[1] = -1;
			//m_pGraph->PaintGraph();
			InvalidateRect(&m_savePlaceHolder2, TRUE);
			m_ctrlCX2.SetWindowText("");
			m_ctrlDif.SetWindowText("");
		}
	}
	else
		TRACE("\nCX und CY liegen ausserhalb!\n");
	
	CDialog::OnRButtonDown(nFlags, point);
}
 
Zuletzt bearbeitet: