I want to scroll image using scroll bar but when i used scrollwindow() function in OnHScroll method,it only scroll button present in dialog box not image.
I have used bitblt and stretchblt function to enlarge image using device context.I think by using dc information we can scroll image but i donot know i to do it.
Code of OnHScroll function is given below:
void CImgVeiwer::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pcrollBar)
{
// TODO: Add your message handler code here and/or call default
int minpos;
int maxpos;
GetScrollRange(SB_HORZ, &minpos, &maxpos);
maxpos = GetScrollLimit(SB_HORZ);
CurPos = GetScrollPos(SB_HORZ);
switch (nSBCode)
{
case SB_LEFT: // Scroll to far left.
CurPos = minpos;
break;
case SB_RIGHT: // Scroll to far right.
CurPos = maxpos;
break;
case SB_ENDSCROLL: // End scroll.
break;
case SB_LINELEFT: // Scroll left.
if (CurPos > minpos)
CurPos--;
break;
case SB_LINERIGHT: // Scroll right.
if (CurPos < maxpos)
CurPos++;
break;
case SB_PAGELEFT: // Scroll one page left.
{
// Get the page size.
SCROLLINFO info;
GetScrollInfo(SB_HORZ, &info, SIF_ALL);
if (CurPos > minpos)
CurPos = max(minpos, CurPos - (int) info.nPage);
}
break;
case SB_PAGERIGHT: // Scroll one page right.
{
// Get the page size.
SCROLLINFO info;
GetScrollInfo(SB_HORZ, &info, SIF_ALL);
if (CurPos < maxpos)
CurPos = min(maxpos, CurPos + (int) info.nPage);
}
break;
case SB_THUMBPOSITION: // Scroll to absolute position. nPos is the position
CurPos = nPos; // of the scroll box at the end of the drag operation.
break;
case SB_THUMBTRACK: // Drag scroll box to specified position. nPos is the
CurPos = nPos; // position that the scroll box has been dragged to.
break;
}
// Set the new position of the thumb (scroll box).
m_HsrollFlag = TRUE;
SetScrollPos(SB_HORZ,CurPos);
ScrollWindow(-CurPos,0,0,0);
Invalidate();
CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}
Thanks In Advance
Finally ,I got solution to scroll image horizontally.
In above given code,remove the statement
ScrollWindow(-CurPos,0,0,0);
and add following statement in OnPaint() method, m_nWidth and nHeight are width and height of image you want to scroll.
dc.StretchBlt(ZERO - CurPos,FIFTY ,m_nWidth +1000,
nHeight+ 1000,
&memDC,ZERO,ZERO,m_nWidth,
m_nHeight,SRCCOPY);
By calling Invalidate() you cause the entire dialog to be repainted. So the ScrollWindow call is wasted: you are overpainting it in the subsequent WM_PAINT. Normally you would use ScrollWindow to scroll the visible part of the image, and then in WM_PAINT you only need to paint the uncovered edge left behind by the image scroll.
You should provide an lpRect parameter to ScrollWindow, and maybe lpClipRect as well. This will specify the area you want scrolled and also prevent the scrolling of child windows like buttons if they are outside of the image.
Related
I'll try to be as clear as I can here. I have this C++ code here that lets me move a shape (circle or square) around a window by clicking (selecting) once on the shape, and then tapping or holding the arrow keys, and it let's me re-size the shape by clicking (selecting) once on the shape and tappping or holding the '+' or '-' keys.
//For extra credit, modify the project so that moving the mouse with the
//left button and the shift key down will change the size of the selected
// object.
afx_msg void CLab09Win::OnKeyDown (UINT achar, UINT repeat, UINT flags) {
CRect modified;
switch(achar) {
case 'B': // 'b'
design.SetColor ('B');
break;
case 38: //up arrow to move shape
modified = design.MoveShape(0, -1);
InvalidateRect(modified);
break;
case 40: //down arrow to move shape
modified = design.MoveShape(0, 1);
InvalidateRect(modified);
break;
case 107: // '+' (numeric pad) to grow shape
modified = design.ResizeShape(2);
InvalidateRect(modified);
break;
case 109: // '-' [numeric pad] to shrink shape
modified = design.ResizeShape(-2);
InvalidateRect(modified);
break;
};
}
I want to simultaneous hold two keys to resize the shape, i.e hold 'X' and 'W', as in x + w or like how we copy something ( Ctrl + C ).
I tried the following code but it didn't work.
case 'X':
if (achar == 'W') {
modified = design.ResizeShape(2);
InvalidateRect(modified);
break;
}
I've had a hard time finding solutions to this online because most solutions use something called VK (virtual keys), and in this assignment we don't use VK.
Ultimately, I actually want to have it so that after selecting a shape, and holding down the SHIFT key while holding the left mouse button and moving the cursor the shape will be re-sized, similar to how you re-size a window by clicking on its edge and dragging the cursor.
My code for handling mouse movement and left-button events is the following:
afx_msg void CLab09Win::OnLButtonDown(UINT flags, CPoint point) {
CRect selected = design.SelectShape(point.x, point.y);
current = point;
InvalidateRect(selected);
}
afx_msg void CLab09Win::OnMouseMove(UINT flags, CPoint point) {
if (flags == MK_LBUTTON) {
int deltax = point.x - current.x;
int deltay = point.y - current.y;
CRect modified = design.MoveShape(deltax, deltay);
current = point;
InvalidateRect(modified);
}
}
So to recap, I would like advice on how to use two keyboard keys [ x + w ] , and how to use a keyboard key along with the mouse's left-button [ SHIFT + LButton ] and the movement of the cursor to resize a shape (circle or square).
Thank you all.
I am working in an MFC windows application. I am using check boxes in Check List Box control (CCheckListBox class) . While disabling a check box, its color remains gray. Is there any way to change the background color from gray to another color?
You can use the DrawItem method to control the rendering of the control and its list items. To do that, you’ll want to derive your own CCheckListBox class and implement that method. For example, I’ve changed the second item in the list to red.
The sample code to do that looks like…
void MyCheckListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
UINT index = lpDrawItemStruct->itemID;
CDC *pDC = CDC::FromHandle (lpDrawItemStruct->hDC);
if (index == 1)
{
CRect rect = lpDrawItemStruct->rcItem;
pDC->FillSolidRect(&rect, RGB(255, 0, 0));
}
CString str;
GetText(index, str);
pDC->DrawText(str, &lpDrawItemStruct->rcItem, DT_LEFT | DT_VCENTER);
}
The above sample only changes the item’s background color. I’ve left the rest of the processing and any extra rendering up to you.
#rrirower's implementation will work but his code needs some modifications.
(1) Changing the Back ground color of the disabled check Box
void CMyCheckListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC dc;
dc.Attach(lpDrawItemStruct ->hDC);
RECT rect = lpDrawItemStruct ->rcItem;
UINT nId=lpDrawItemStruct->itemID;
CString strItemText;
GetText(lpDrawItemStruct ->itemID, strItemText);
if(nId==1 ||nId==3){
dc.FillSolidRect(&rect,RGB(255,0,0));
dc.DrawText(strItemText , &rect, DT_LEFT | DT_VCENTER);
}
else{
CCheckListBox::DrawItem(lpDrawItemStruct);
}
dc.Detach();
}
(2) Changing the Disabled check list box text color
replace dc.FillSolidRect(&rect,RGB(255,0,0)); with dc.SetTextColor(RGB(255,0,0));
I'm currently working on project which will have two RichEdit controls one close to the other: let's say RichEdit1 is on left and RichEdit2 is on the right.
The user scenario I want to enable in the project is:
User mouse LButton down at somewhere in RichEdit1, e.g. before the 3rd char, in total 7 chars.
User drag the mouse to RichEdit2, e.g. after the 6th char, in total 11 chars.
User mouse LButton up.
I want to see both RichEdit1 3rd char to end and RichEdit2 begin to 6th char are selected.
Currently I notice that once mouse LButton down on RichEdit1, after I move the mouse to RichEdit2, the RichEdit2 could not receive mouse event before I release mouse.
Any suggestion will be appreciated. Thank you!
When the mouse button is pressed down on RichEdit1, it captures the mouse, thus subsequent mouse messages are sent to RichEdit1 until the mouse button is released. That is why RichEdit2 does not receive any mouse events while dragging over RichEdit2.
You will have to process the mouse move messages in RichEdit1 and check if their coordinates are outside of RichEdit1's client area. If so, convert them into coordinates relative to RichEdit2's client's area and then send EM_SETSEL/EM_EXSETSEL messages to RichEdit2 as needed. For example:
int RichEdit2StartIndex = -1;
...
// in RichEdit1's message handler...
case WM_MOUSEMOVE:
{
if ((wParam & MK_LBUTTON) == 0)
break;
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
RECT r;
GetClientRect(hwndRichEdit1, &r);
if (xPos < (r.right - r.left))
{
if (RichEdit2StartIndex != -1)
{
SendMessage(hwndRichEdit2, EM_SETSEL, -1, 0);
RichEdit2StartIndex = -1;
}
}
else
{
POINT pt;
pt.x = xPos;
pt.y = yPos;
MapWindowPoints(hwndRichEdit1, hwndRichEdit2, &pt, 1);
POINTL pl;
Pl.x := pt.x;
Pl.y := pt.y;
int idx = SendMessage(hwndRichEdit2, EM_CHARFROMPOS, 0, (LPARAM)&Pl);
if (idx != -1)
{
if (RichEdit2StartIndex == -1)
RichEdit2StartIndex = idx;
SendMessage(hwndRichEdit2, EM_SETSEL, RichEdit2StartIndex, idx);
}
}
break;
}
Vice versa when dragging a selection from RichEdit2 to RichEdit1.
And make sure that both RichEdit controls have the ES_NOHIDESEL style applied so you can see the selection in both controls at the same time.
I'm designing a custom window border, and i put a bitmap on the top as a drag bar. This works, however when i try to drag the window, it places itself in two different areas and flickers between the two. Here's a video:
http://dl.dropbox.com/u/85700751/capture-1.avi
When the window is flashing, i'm trying to drag it (it doesn't show my cursor for some reason). Here's my dragging code:
case WM_LBUTTONDOWN: {
int posX = LOWORD(lParam);
int posY = HIWORD(lParam);
if((isDragging==false)&&(posX>4)&&(posX<470)&&(posY>4)&&(posY<24))
{
isDragging = true;
ClipCursor(rect);
oldCursorX = posX;
oldCursorY = posY;
}
}
break;
case WM_LBUTTONUP: {
isDragging = false;
ClipCursor(NULL);
}
break;
case WM_MOUSEMOVE: {
if(isDragging) {
SetWindowPos(hWnd, NULL, LOWORD(lParam)-oldCursorX, HIWORD(lParam)-oldCursorY, 500, 500, NULL);
}
}
break;
It's generally easiest to simply resond to WM_NCHITTEST. For that message, the LPARAM will have the mouse hit X and Y coordinates (same as WM_LBUTTONDOWN). If they're within your draggable area just return HTCAPTION. The system will then automatically handle all the drag logic for you.
The cursor coordinates passed to WM_MOUSEMOVE are relative to the window position. But you keep changing the window position with every WM_MOUSEMOVE recieved.
Convert the coordinates to Screen coordinates using ::ClientToScreen().
I have a list view where I want to disable the horizontal scroll bar.
Basically, I know none of my data will exceed the width of the single column, but if enough entries get added to the list view, the vertical scroll bar pops up, reducing the width available, making the horizontal scroll bar pop up.
I was thinking about some how catching a message right before the vertical scroll bar gets added, and then re-sizing the column to make enough room, but I don't know what message I would need to catch to do this.
EDIT:
Does anyone know if there is a message sent after an item in a list view is deleted? LVN_ITEMCHANGED appeared to only be sent after an item is added. And LVN_DELETEITEM only before an item is deleted.
You could send the message: LVM_SETCOLUMNWIDTH to the listview with cx param set to LVSCW_AUTOSIZE_USEHEADER
Well I worked out one solution.
There is a bug though, if I only remove one item it doesn't resize the column.
case LVN_DELETEITEM:
{
LPNMLISTVIEW listView = (LPNMLISTVIEW) lParam;
// After an item is deleted,
// if there is not a vertical scroll bar and GWL_USERDATA is TRUE,
// resize the column back to normal.
if (!(GetWindowLong(listView->hdr.hwndFrom, GWL_STYLE) & WS_VSCROLL) &&
GetWindowLong(listView->hdr.hwndFrom, GWL_USERDATA) == TRUE)
{
const int ColWidth = ListView_GetColumnWidth(listView->hdr.hwndFrom, 0);
ListView_SetColumnWidth(listView->hdr.hwndFrom, 0, ColWidth + GetSystemMetrics(SM_CXVSCROLL));
SetWindowLong(listView->hdr.hwndFrom, GWL_USERDATA, FALSE);
}
break;
}
case LVN_ITEMCHANGED:
{
LPNMLISTVIEW listView = (LPNMLISTVIEW) lParam;
// After an item is added, if there is a horizontal scrollbar,
// resize the column and set GWL_USERDATA to TRUE.
if (GetWindowLong(listView->hdr.hwndFrom, GWL_STYLE) & WS_HSCROLL)
{
const int ColWidth = ListView_GetColumnWidth(listView->hdr.hwndFrom, 0);
ListView_SetColumnWidth(listView->hdr.hwndFrom, 0, ColWidth - GetSystemMetrics(SM_CXVSCROLL));
SetWindowLong(listView->hdr.hwndFrom, GWL_USERDATA, TRUE);
}
break;
}
I'd still love to see a better solution, but this works for now.