As follow code, I want use mpDC to draw a cross line on mouse point,
when I move the mouse, the cross line will shift with my mouse point,
but maybe I dont know the usage of BitBlt, so I cant see any line in my draw area
(rectRange),
CWnd *pWnd;
CRect rect;
CDC mShowDC;
CBitmap mShowBmp;
CPen mpen;
CPen *mOldpen;
CDC *mpDC;
mpDC = GetDC();
mShowDC.CreateCompatibleDC(mpDC);
mShowBmp.CreateCompatibleBitmap(mpDC,rectRange.Width(),rectRange.Height());
mShowDC.SelectObject(mShowBmp);
BitBlt(mShowDC,0,0,rectRange.Width(),rectRange.Height(),
mbkCurveDC,0,0,SRCCOPY);
//InvalidateRect(rectRange);
if(boolShowMouseLine)
{
mpen.CreatePen(PS_SOLID,1,RGB(0,0,0));
mOldpen = mShowDC.SelectObject(&mpen);
mShowDC.MoveTo(rectRange.left,mMousePoint.y);
mShowDC.LineTo(mMousePoint.x - 1,mMousePoint.y);
mShowDC.MoveTo(mMousePoint.x + 1,mMousePoint.y);
mShowDC.LineTo(rectRange.bottom,mMousePoint.y);
mShowDC.MoveTo(mMousePoint.x,rectRange.top);
mShowDC.LineTo(mMousePoint.x,mMousePoint.y - 1);
mShowDC.MoveTo(mMousePoint.x,mMousePoint.y + 1);
mShowDC.LineTo(mMousePoint.x,rectRange.right);
mpen.DeleteObject();
mShowDC.SelectObject(mOldpen);
}
mpDC->BitBlt(rectRange.left, rectRange.top,
rectRange.Width(), rectRange.Height(),
&mShowDC, rectRange.left, rectRange.top, SRCCOPY);
My another method to draw cross line as follow code
CDC *cdc;
cdc = GetDC();
if(boolShowMouseLine)
{
cdc->MoveTo(rectRange.left,mMousePoint.y);
cdc->LineTo(mMousePoint.x - 1,mMousePoint.y);
cdc->MoveTo(mMousePoint.x + 1,mMousePoint.y);
cdc->LineTo(rectRange.right,mMousePoint.y);
cdc->MoveTo(mMousePoint.x,rectRange.top);
cdc->LineTo(mMousePoint.x,mMousePoint.y - 1);
cdc->MoveTo(mMousePoint.x,mMousePoint.y + 1);
cdc->LineTo(mMousePoint.x,rectRange.bottom);
}
Current situation is the picture
but this code will draw many cross line when shift the mouse location,
How do I Clear the previous cross line...
the key point to do this without using bitmap is cdc->SetROP2(R2_NOT).
and you should record the point for the last drawing.
I try to test it by the following steps, hope is will help
define CPoint m_lastPoint in C**view
Initilize m_lastPoint = CPoint(-100,-100) in C**view construct function
add OnMouseMove function for the message WM_MOUSEMOVE or other message you want to add.
CDC *cdc;
cdc = GetDC();
CPoint mMousePoint = point;
CRect rectRange;//(0,0,500,500);
GetClientRect(&rectRange);
if(m_lastPoint.x >= 0 && m_lastPoint.y >= 0)
{
cdc->SetROP2(R2_NOT);
mMousePoint = m_lastPoint;
cdc->MoveTo(rectRange.left,mMousePoint.y);
cdc->LineTo(mMousePoint.x - 1,mMousePoint.y);
cdc->MoveTo(mMousePoint.x + 1,mMousePoint.y);
cdc->LineTo(rectRange.right,mMousePoint.y);
cdc->MoveTo(mMousePoint.x,rectRange.top);
cdc->LineTo(mMousePoint.x,mMousePoint.y - 1);
cdc->MoveTo(mMousePoint.x,mMousePoint.y + 1);
cdc->LineTo(mMousePoint.x,rectRange.bottom);
}
cdc->SetROP2(R2_BLACK);
mMousePoint=point;
cdc->MoveTo(rectRange.left,mMousePoint.y);
cdc->LineTo(mMousePoint.x - 1,mMousePoint.y);
cdc->MoveTo(mMousePoint.x + 1,mMousePoint.y);
cdc->LineTo(rectRange.right,mMousePoint.y);
cdc->MoveTo(mMousePoint.x,rectRange.top);
cdc->LineTo(mMousePoint.x,mMousePoint.y - 1);
cdc->MoveTo(mMousePoint.x,mMousePoint.y + 1);
cdc->LineTo(mMousePoint.x,rectRange.bottom);
m_lastPoint = mMousePoint;
Ok, found an answer for you that doesn't use BitBlt based on micaheltang's answer:
When drawing the line, first call cdc->SetROP2(R2_XORPEN); as stated here http://books.google.co.il/books?id=eDvx4Qx63b0C&pg=PA105&lpg=PA105&dq=MFC+blending+line+with+background&source=bl&ots=v3ycFSlHL7&sig=agpZHLBgnocSXZLQ6qSM6nWFIzM&hl=en&sa=X&ei=wZ_XUsOvLYXStAa054H4Cw&ved=0CCoQ6AEwAA#v=onepage&q=MFC%20blending%20line%20with%20background&f=false under Line Blending. When erasing the line use the same mode and it should restore the previous color.
I use as follow code
CClientDC dc(this);
int oldmode=dc.SetROP2(R2_NOTXORPEN);
COLORREF color;
color = RGB(0,0,0);
CPen pen(PS_DASH, 2, color), *oldpen;
oldpen = dc.SelectObject(&pen);
dc.MoveTo(rectRange.left, mMousePoint.y);
dc.LineTo(mMousePoint.x - 1, mMousePoint.y);
dc.MoveTo(mMousePoint.x + 1, mMousePoint.y);
dc.LineTo(rectRange.right, mMousePoint.y);
dc.MoveTo(mMousePoint.x, rectRange.top);
dc.LineTo(mMousePoint.x, mMousePoint.y - 1);
dc.MoveTo(mMousePoint.x, mMousePoint.y + 1);
dc.LineTo(mMousePoint.x, rectRange.bottom);
PEndPoint = point;
dc.MoveTo(rectRange.left, mMousePoint.y);
dc.LineTo(mMousePoint.x - 1, mMousePoint.y);
dc.MoveTo(mMousePoint.x + 1, mMousePoint.y);
dc.LineTo(rectRange.right, mMousePoint.y);
dc.MoveTo(mMousePoint.x, rectRange.top);
dc.LineTo(mMousePoint.x, mMousePoint.y - 1);
dc.MoveTo(mMousePoint.x, mMousePoint.y + 1);
dc.LineTo(mMousePoint.x, rectRange.bottom);
dc.SelectObject(oldpen);
dc.SetROP2(oldmode);
ReleaseDC(&dc);
the cross line will reflash, but no keep in screen, how fixed it.
Related
I am trying to create a timeline app for visualization of certain time-sensitive requirements information and have begun experimentation with Qt since I am new to it. The problem I am having is that the rendered object will show up if I render it just basically on the main background, but when I tried to add the TimeLine objects to the vertical layout I have on my UI they refuse to render.
Here is my main window code for creating the objects:
void MainWindow::drawTimelines()
{
for(int i=0; i <= 3; i++)
{
TimeLine *tl = new TimeLine(this, this);
// ui->verticalLayout->addWidget(tl, 0, Qt::AlignLeft);
tl->lower();
QPoint * dest = new QPoint(this->width() - (this->width() / 12), i * this->height() / 4 + this->height() / 4);
QPoint * src = new QPoint(this->width() / 12, i * this->height() / 4 + this->height() / 4);
// tl->setGeometry(0, 0, this->width(), 100);
tl->setGeometry(src->x(), src->y(), this->width(), 100);
tl->updateGeometry();
QPoint *startPt = new QPoint(src->x(), 50);
QPoint *endPt = new QPoint(dest->x(), 50);
// QPoint *src = new QPoint(this->width() /8, 50);
// QPoint *dest = new QPoint(this->width() - (this->width() / 8), 50);
tl->setSrcPt(startPt);
tl->setDestPt(endPt);
tl->setNumSegments(3);
timeLineList.push_back(tl);
timeLineList.at(i)->show();
}
update();
}
Here is the maint function present in the TimeLine object itself:
void TimeLine::paintEvent(QPaintEvent * event)
{
QRectF frame(QPointF(sourcePoint->x(), sourcePoint->y()), geometry().size());
QPainter painter(this);
painter.setPen(QPen(Qt::FlatCap));
painter.drawRoundedRect(frame, 10.0, 10.0);
int translateAmount = sourcePoint->y() - window->getPainterY();
painter.translate(0, translateAmount);
// window->setPainterY(translateAmount);
painter.drawLine(sourcePoint->x(), 25, destPoint->x(), 25);
for(int i = 0; i <= numSegments; i++){
int xPoint = ((destPoint->x() - sourcePoint->x()) * i / numSegments) + sourcePoint->x();
int yPoint = 25;
painter.drawLine(xPoint, yPoint + 20, xPoint, yPoint - 20);
}
QWidget::paintEvent(event);
}
For reference, the verticalLayout is meant to have one
The TimeLines (and bounded rect boxes) do not render when I have the
// ui->verticalLayout->addWidget(tl, 0, Qt::AlignLeft);
uncommented. As you can see from a bunch of the other commented lines, I have tried numerous other things to try and render these TimeLines. I have tried:
changing reference points of the geometry to be (0,0) for the new segment of the vertical layout
changing the size of the geometry
both translating and not translating the painter
changing line thickness, type of line, etc.
even tried rendering something else simple in the vertical layout
The part that confuses me is that even the bounded rect made based on the geometry of the TimeLine frame gets cut off on the side and top of the timeline (it only shows top left corner and the top and left side-lines) even when rendered on the normal screen.
I'm struggling with displaying of an int in WinApi in C++. I have a drawing function
void MyOnPaint(HDC hdc)
{
Graphics graphics(hdc);
Pen pen(Color(255, 0, 0, 255));
Pen pen2(Color(255, 25*col, 0, 255));
for (int i = 1; i < 100; i++)
graphics.DrawLine(&pen2, data[i - 1].X, data[i - 1].Y, data[i].X, data[i].Y);
graphics.DrawRectangle(&pen, 50 + value, 400, 10, 20);
}
And i would like to display an integer (for example value) every time the method is called (the value of value keeps changeing so it it would be updating every time I call the method).
I heard something about Graphics.DrawString but I don't know how to use it.
Convert the int to string (a sequence of characters), e.g. using std::to_wstring. Draw the string. API functions like DrawString help tremendously with the latter.
I have a 32bpp bitmap image which has an alpha channel with values ranging from 0-255. I am trying to display this in a window using win32 APIs (snippet of code I am using to display is appended).
I was reading the documentation and it turns out that for blending, in the case where I want to use per-pixel values, windows uses the following formula:
Dst.Red = Src.Red + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Green + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Blue + (1 - Src.Alpha) * Dst.Blue
This is weird. I would have expected it to use:
Dst.Red = Src.Alpha*Src.Red + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Alpha*Src.Green + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Alpha*Src.Blue + (1 - Src.Alpha) * Dst.Blue
because that is what creates the overlay effect (translucency).
Is my expectation correct? If yes, why is windows doing the blending in this manner? What am I missing here?
snippet of code I am using to paint the Layered Window:
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
POINT ptOrigin = { 0, 0 };
SIZE windowSize = { 300, 300 };
POINT ptZero = { 0, 0 };
UpdateLayeredWindow(m_sThis->m_hWnd, dc, &ptOrigin, &windowSize,
hdc, &ptZero, RGB(255, 255, 255), &bf, ULW_ALPHA);
From the documentation:
Note that the APIs use premultiplied alpha, which means that the red,
green and blue channel values in the bitmap must be premultiplied with
the alpha channel value. For example, if the alpha channel value is x,
the red, green and blue channels must be multiplied by x and divided
by 0xff prior to the call.
So, you are right, but you have to do it by hand before.
So, I'm trying to acquire the x-y coordinates of the CORNERS of my MFC window...
Here's what I have so far in my draw function:
// TODO: add draw code for native data here
RECT rect;
GetClientRect(&rect);
// Get window coordinates
int left = rect.left;
int right = rect.right;
int bottom = rect.bottom;
int top = rect.top;
// Print them out
CString l;
l.Format(L"%d", left);
pDC->TextOutW(0, 100, L"Left: " + l, _tcslen(l)+6);
CString r;
r.Format(L"%d", right);
pDC->TextOutW(0, 130, L"Right: " + r, _tcslen(r)+7);
CString b;
b.Format(L"%d", bottom);
pDC->TextOutW(0, 160, L"Bottom: " + b, _tcslen(b)+8);
CString t;
t.Format(L"%d", top);
pDC->TextOutW(0, 190, L"Top: " + t, _tcslen(t)+5);
Am I headed in the right direction?
I was thinking I could find the midpoint of the two or something along those lines....
What else do I need to do?
Also: How would I acquire the x-y coordinates of the corners of my physical display as well?
Use the GetWindowRect function instead of the GetClientRect function.
You also may have a look at the ScreenToClient and the ClientToScreen functions.
Adding something to "Left: " is invalid. Use the Format statement to build the entire string to be displayed, and use the CString::GetLength() method if you need the length. (There is a version of TextOut that accepts a CString without the length parameter.)
Okay I am having some problems with being able to change bitmaps when a certain parameter is greater than another. I am a massive newbie to this and my coding isn't great (at all). I have code that reads the limits (parameters) and displays as text which is this:
CFont* def_font = argDC->SelectObject(&m_Font);
CString csText;
int StartPos = WindowRect.Width()/5;
CRect TextRect(StartPos, WindowRect.top + 5, StartPos + 100, WindowRect.top + 35);
csText.Format(_T("%.2ft"), argSystemDataPtr->GetMaxSWL());
int32_t iSWLDigits = csText.GetLength();
if (iSWLDigits < m_SWLDigitsNum)
{
m_RedPanelBitmap.LoadBitmapW(IDB_BITMAP_PANEL_RED);
//argDC->FillSolidRect(TextRect, RGB(255, 255, 255));
}
m_SWLDigitsNum = iSWLDigits;
argDC->DrawText(csText, TextRect, DT_LEFT);
The bitmaps that are usually displayed are green but if a limit is breached like the one above then I want the bitmap to change to a red one. Here is what I've got for the green ones.
CRect PanelRect1, PanelRect2;
CRect PanelsRect(WindowRect);
const int BarHeight = 30;
PanelsRect.OffsetRect(0,m_bShowTitleBar?BarHeight:-BarHeight);
PanelsRect.DeflateRect(0,m_bShowTitleBar?BarHeight*-1:BarHeight);
m_GreenPanelBitmap.Detach();
m_GreenPanelBitmap.LoadBitmapW(IDB_BITMAP_PANEL_GREEN);
CBitmap* pOld = memDC.SelectObject(&m_GreenPanelBitmap);
BITMAP bits;
m_GreenPanelBitmap.GetObject(sizeof(BITMAP),&bits);
PanelRect1.SetRect(0,PanelsRect.top, PanelsRect.right /2 , PanelsRect.Height()/3);
PanelRect2.SetRect(0,PanelsRect.top+PanelRect1.Height(), PanelsRect.right /2 ,(PanelsRect.Height()/3) + PanelRect1.Height());
//Now draw the Panels
if (pOld != NULL)
{
argDC->StretchBlt(PanelRect1.left ,PanelRect1.top,PanelRect1.Width(),PanelRect1.Height(),
&memDC,0,0,bits.bmWidth-1, bits.bmHeight-1, SRCCOPY);
argDC->StretchBlt(PanelRect2.left,PanelRect2.top,PanelRect2.Width(),PanelRect2.Height(),
&memDC,0,0,bits.bmWidth-1, bits.bmHeight-1, SRCCOPY);
memDC.SelectObject(pOld);
I would be extremely grateful for any help, I understand there probably is a simple answer but I've been scratching my head over it and can't seem to find an answer anywhere else on how change the m_GreenPanelBitmap to m_RedPanelBitmap when this statement is true.
`if (iSWLDigits < m_SWLDigitsNum).`
Well, I do think your question is a bit messy but...
On the second code snippet you posted (I suppose from a OnPaint method in a dialog) you are displaying the green bitmap by using StretchBlt.
If your problem is you need to display one bitmap or another depending on a condition you should load both images (maybe you can do that elsewhere to avoid loading the images everytime the dialog is painted) and then display the one you really need based on the condition. Something like that:
bool bCondition = /*whatever*/
m_GreenPanelBitmap.LoadBitmapW(IDB_BITMAP_PANEL_GREEN);
m_RedPanelBitmap.LoadBitmapW(IDB_BITMAP_PANEL_RED);
CBitmap* pBitmapToDisplay = bCondition ? &m_GreenPanelBitmap : &m_RedPanelBitmap;
CBitmap* pOld = memDC.SelectObject(pBitmapToDisplay);
BITMAP bits;
pBitmapToDisplay->GetObject(sizeof(BITMAP),&bits);
PanelRect1.SetRect(0,PanelsRect.top, PanelsRect.right /2 , PanelsRect.Height()/3);
PanelRect2.SetRect(0,PanelsRect.top+PanelRect1.Height(), PanelsRect.right /2, PanelsRect.Height()/3) + PanelRect1.Height());
argDC->StretchBlt(PanelRect1.left ,PanelRect1.top,PanelRect1.Width(),PanelRect1.Height(),
&memDC,0,0,bits.bmWidth-1, bits.bmHeight-1, SRCCOPY);
memDC.SelectObject(pOld);
Maybe with a more detailed question we would be able to help you more.