CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16
  1. #1
    Join Date
    Jul 2004
    Posts
    148

    URGENT- Asked This Question Twice Already

    Hi:

    I asked this before as stated in the title, but so far no one has even replied Let me try to ask it again. What I am trying to do is draw a vertical "ruler line" on the screen which follows this csliderctrl in a cdialogbar above the view. So basically, as u move the slider, the line moves along with it (it should always be directly beneath the tip of the slider). The following is a relevant code snippet:

    Code:
    	CSize size(10000,10000);
    	pDC->DPtoHIMETRIC(&size);
    	if (pFrame->m_dTopBar.drawLine == TRUE)
    	{
    		newpen.CreatePen (PS_SOLID,1,RGB (204,204,204));
    		oldpen = pDC->SelectObject(&newpen);
    		pDC->MoveTo((int)(size.cx/10000.0*(pFrame->m_dTopBar.curPos*(double)(tChanRect.Width()-tThumbRect.Width())/(pFrame->m_dTopBar.maxPos+1)+tChanRect.left+(tThumbRect.Width())/2)+xOffset),0);
    		pDC->LineTo((int)(size.cx/10000.0*(pFrame->m_dTopBar.curPos*(double)(tChanRect.Width()-tThumbRect.Width())/(pFrame->m_dTopBar.maxPos+1)+tChanRect.left+(tThumbRect.Width())/2)+xOffset),2*rect.Height()*YCON_FCTR);
    		pDC->SelectObject(oldpen);
    		newpen.DeleteObject();
    	}
    Most of the variables are self-explanatory (I hope), I am currently using MM_HIMETRIC as my mapping mode. What the above piece of code pretty much tries to do is calculate the position of the tip of the slider in pixels by taking its current position, and multiplying it by a conversion factor(ie. the length of the slider divided by the range of the slider). I then add a little offset to account for the fact that the beginning of the slider is not the beginning of the csliderctrl (the xOffset variable should be ignored as it is only used for scrolling purposes inside my program, and it works perfectly). The problem appears to be that the line starts off a little to the right of the slider's tip, but then if you slide the slider to the other end (ie. the right end), it will be perfectly underneath the tip. This represents a 2 problems: Not only is the offset apparently incorrect, the line is not travelling at the same "speed" as the slider, because if it was then at the end of the slider, the line would still be a little to the right instead of being directly underneath. I have tried adding/subtracting 1, 1.5 or 2 from various of the variables above to try and correct the problem, and it works, but only for the resolution at which I am working at, and not at any others which means that I am not really getting to the heart of the matter, but merely "fudging" the data. I need this to be pretty accurate, which is why this is a problem, does anyone have any ideas. I would welcome ANY, no matter how outrageous, solutions/ideas to this problem, as I am really stuck.

  2. #2
    Join Date
    Feb 2002
    Posts
    4,640

    Re: URGENT- Asked This Question Twice Already

    Why are you dividing your size values by 10000.0? Also, couldn't you just get the position of the slider (GetClientRect), and use it's position exactly? I've never used a slider, though.

    If you can't use the slider position directly, I'm guessing that it has a "position" within a "range" (like Microsoft's progress bar). If that's the case, then the position of the slider is just a "percentage" of the total slider. Get that percentage, and multiply it by the left coordinate of the actual slider position (again, using GetClientRect/GetWindowRect).

    VIggy

  3. #3
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: URGENT- Asked This Question Twice Already

    I'll take a stab at it (but I have not used sliders in this level of intricacy, so watch out).

    I think curPos is the integer value that's return by GetPos, and if so, then remember that it's a value between GetRangeMax and GetRangeMin which is not necessarily the same a GetRangeMax and "zero". I'll call those minPos and maxPos, respectively.

    So, your horizontal (x) position should be something like:

    ((double)(curPos - minPos)*(chanRect.Width() - thumbRect.Width()))/(double)(maxPos - minPos) + chanRect.Left() + thumbRect.Width()/2

    I left out your scaling by 10000 since I didn't understand it. Maybe you should make the above calculation and then call DPtoHIMETRIC on the answer.

    If you still have no luck, then maybe send a screen shot of what it looks like now.

    Best,
    Mike

  4. #4
    Join Date
    Jul 2004
    Posts
    148

    Re: URGENT- Asked This Question Twice Already

    FINALLY !!! Some answers - thnx guys.

    Mr. Viggy : Hmm, I never thought of your idea, but I think I will definitely give it a try.

    MikeAThon: Also an interesting approach, I will have to give that a try. Your idea of calling DPtoHIMETRIC on the answer might be a better approach. Just to note that I have set the minPos to 0 in other functions inside the my cdialogbar class, so in essence I am subtracting 0.

    Hmm, I have seemed to have confused people about the size thing. If you will note in my call to DPtoHIMETRIC, I pass in (10000,10000) as arguments, which is why I divide it by 10,000 later in my calls to LineTo and MoveTo. The reason behind it is because I wanted to use it as a conversion factor, and before, if 1 pixel was equal to 23.475 in HIMETRIC, then passing (1,1) into the DPtoHIMETRIC function would return only 23, because it only returns int's. If I want to preserve the decimal, I just pass in a larger number, and then divide later, so in essence I "stall" the conversion into int until a later time. However, as suggested, I might just call DPtoHIMETRIC on the result, rather then use the conversion factor.

    I will post my results after I try your suggestions. Keep the answers coming

  5. #5
    Join Date
    Jul 2004
    Posts
    148

    Re: URGENT- Asked This Question Twice Already

    Well, I have tried both solutions, with mixed results:

    Mr.Viggy: Instead of making curPos the value of GetPos() in my OnHSscroll function, I just used GetThumbRect, and then set curPos = rect.left+rect.Width(). It lines up correctly now in the beginning, but again for my resolution only (1280X1024), and then it starts to lag behind quite a bit when you start to move it, even though I don't know why. When I switched to a resolution of 640X480, then it lines up a little to the right, but seems to move at the same speed as the slider.

    MikeAThon: Your solution works, but only in the sense that it does the same thing as what I had before (albeit without that needless conversion). As for posting screen shots, do you get screenshots by pressing the "Print Scrn" button on the keyboard? Where are the images stored? As well, since the problem is pretty slight, you might not be able to see it, but I will post it just the same when I can.

    And some other questions: What are the units of the values returned by GetThumbRect and GetChannelRect? What about GetClientRect/GetWindowRect?
    When MSDN says pixel, do they mean pixel as in my resolution is 1280 X 1024 pixels? Or do they mean something else? Is a device unit dependent on the mapping mode? Like for MM_HIMETRIC, 1 device unit is equal to 0.001 mm (or as close as possible)? Is a logical unit just an arbitraray construct, and has no real physical meaning except that given to it by a mapping mode? Because I am questioning my use of DPtoHIMETRIC, maybe the problem lies in there.

    I mean there has to be some way to draw that line perfectly, as the framework renders the tip correctly, and so if only I could get the coordinates of that point Sorry for what seems to be a barrage of questions, but it would greatly help and increase my understanding of what is going on

  6. #6
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: URGENT- Asked This Question Twice Already

    The following code works absolutely fine for me, as shown in the attached screen shots.

    The code is in the CView-derived class of a standard AppWizard MDI application. The only other thing you need to test it is to add a CSlider member object named m_ctlSlider:

    Code:
    // TrackTestView.cpp : implementation of the CTrackTestView class
    //
    
    #include "stdafx.h"
    #include "TrackTest.h"
    
    #include "TrackTestDoc.h"
    #include "TrackTestView.h"
    
    #include <afxcmn.h>
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CTrackTestView
    
    IMPLEMENT_DYNCREATE(CTrackTestView, CView)
    
    BEGIN_MESSAGE_MAP(CTrackTestView, CView)
    	//{{AFX_MSG_MAP(CTrackTestView)
    	ON_WM_CREATE()
    	ON_WM_SIZE()
    	ON_WM_HSCROLL()
    	//}}AFX_MSG_MAP
    	// Standard printing commands
    	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
    	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
    	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CTrackTestView construction/destruction
    
    CTrackTestView::CTrackTestView()
    {
    	// TODO: add construction code here
    
    }
    
    CTrackTestView::~CTrackTestView()
    {
    }
    
    BOOL CTrackTestView::PreCreateWindow(CREATESTRUCT& cs)
    {
    	// TODO: Modify the Window class or styles here by modifying
    	//  the CREATESTRUCT cs
    
    	return CView::PreCreateWindow(cs);
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CTrackTestView drawing
    
    void CTrackTestView::OnDraw(CDC* pDC)
    {
    	CTrackTestDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    
    	int curPos, minPos, maxPos;
    	CRect chanRect, thumbRect, sliderRect;
    
    	curPos = m_ctlSlider.GetPos();
    	m_ctlSlider.GetRange( minPos, maxPos);
    	m_ctlSlider.GetThumbRect( &thumbRect );
    	m_ctlSlider.GetChannelRect( &chanRect );
    	m_ctlSlider.GetClientRect( &sliderRect );
    	m_ctlSlider.ClientToScreen( &sliderRect );
    	ScreenToClient( &sliderRect );
    
    	CPen newpen;
    	newpen.CreatePen (PS_SOLID,1,RGB (204,204,204));
    	CPen* oldpen = pDC->SelectObject(&newpen);
    
    	int xPos = (int)( 
    		( (double)(curPos - minPos)*(chanRect.Width() - thumbRect.Width()) )
    		/ (double)(maxPos - minPos) 
    		+ chanRect.left + thumbRect.Width()/2 + sliderRect.left
    		) ;
    	
    	pDC->MoveTo( xPos, 40 );	// both the "40" and the "200"
    	pDC->LineTo( xPos, 200 );	// are arbitrary
    	pDC->SelectObject(oldpen);
    	newpen.DeleteObject();
    
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CTrackTestView printing
    
    BOOL CTrackTestView::OnPreparePrinting(CPrintInfo* pInfo)
    {
    	// default preparation
    	return DoPreparePrinting(pInfo);
    }
    
    void CTrackTestView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO: add extra initialization before printing
    }
    
    void CTrackTestView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO: add cleanup after printing
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CTrackTestView diagnostics
    
    #ifdef _DEBUG
    void CTrackTestView::AssertValid() const
    {
    	CView::AssertValid();
    }
    
    void CTrackTestView::Dump(CDumpContext& dc) const
    {
    	CView::Dump(dc);
    }
    
    CTrackTestDoc* CTrackTestView::GetDocument() // non-debug version is inline
    {
    	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTrackTestDoc)));
    	return (CTrackTestDoc*)m_pDocument;
    }
    #endif //_DEBUG
    
    /////////////////////////////////////////////////////////////////////////////
    // CTrackTestView message handlers
    
    int CTrackTestView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
    {
    	if (CView::OnCreate(lpCreateStruct) == -1)
    		return -1;
    
    	DWORD dwStyle = TBS_HORZ | TBS_NOTICKS | WS_CHILD | WS_VISIBLE;
    
    	m_ctlSlider.Create( dwStyle, CRect(1,2,3,4), this, 1245);
    
    	m_ctlSlider.SetRange( -100, 200, FALSE );
    	
    	return 0;
    }
    
    void CTrackTestView::OnSize(UINT nType, int cx, int cy) 
    {
    	CView::OnSize(nType, cx, cy);
    
    	CRect rc;
    	
    	GetClientRect( &rc );
    
    	m_ctlSlider.SetWindowPos( this, rc.left+25, rc.top, rc.Width()-50,	// arbitrary offsets
    		40 /* fixed arbitrarily at 40 */, SWP_NOZORDER );	
    	
    }
    
    void CTrackTestView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
    {
    	// CSlider sends us WM_HSCROLL messages
    	// just respond by invalidating entire window rect
    
    	Invalidate();	
    	CView::OnHScroll(nSBCode, nPos, pScrollBar);
    }
    Here are a series of three screen shots, pasted together:
    Attached Images Attached Images  

  7. #7
    Join Date
    Jul 2004
    Posts
    148

    Re: URGENT- Asked This Question Twice Already

    The thing is, I want this to be accurate as possible, and while your screenshots would appear to show that your method works, the thing is that the error I am talking about is 1 pixel (it is 1 pixel to the right of what it should be), which is why I was reluctant to use screenshots as they probably wouldn't be capable of showing such an error. The reason why I am so concerned about such a seemingly insignificant error is that I want to ensure that my line draws correctly on all resolutions and on all monitors, something which I cannot really ensure right now, as my conversion is not perfect. This slight error becomes more noticeable the lower the resolution, and possibly on other, high quality monitors, and more importantly this error represents a flaw in my code/reasoning, which I would like to correct.

    I have a few questions about your method: Why did you call ClientToScreen, then call ScreenToClient on the same CRect? Don't the two just cancel each other? And also, how are client coordinates and screen coordinates related? Are they using the same units, or do client coordinates use logical units while screen ones use device units? I am a little confused, and would appreciate it if you could enlighten me

    Finally, if some one could answer the group of questions I had in my previous post that would be greatly appreciated.

  8. #8
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: URGENT- Asked This Question Twice Already

    Look at the screenshots carefully; they indeed are accurate with zero pixel error.

  9. #9
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: URGENT- Asked This Question Twice Already

    We were definitely overthinking this problem.

    To get the position of the tip of the slider's thumb, simply get the thumb's rectangle, get its center point, and then convert to client coordinates. For example:
    Code:
    	CRect thumbRect;
    
    	m_ctlSlider.GetThumbRect( &thumbRect );
    	m_ctlSlider.ClientToScreen( &thumbRect );
    	ScreenToClient( &thumbRect );
    
    	CPen newpen;
    	newpen.CreatePen (PS_SOLID,1,RGB (204,204,204));
    	CPen* oldpen = pDC->SelectObject(&newpen);
    
    	int xPos = thumbRect.CenterPoint().x;
    	pDC->MoveTo( xPos, 40 );	// both the "40" and the "200"
    	pDC->LineTo( xPos, 200 );	// are arbitrary
    	pDC->SelectObject(oldpen);
    	newpen.DeleteObject();
    Here's a screen shot showing four slider controls, as mentioned in another one of your posts, as well as a zipped up project. The screen shot includes a zoomed-in view of the tip of one slider, The attached zip file, incidentally, contains a release executable, so you can check that it's got zero pixel error.


    Mike
    Attached Images Attached Images  
    Attached Files Attached Files
    Last edited by MikeAThon; September 1st, 2004 at 12:34 AM.

  10. #10
    Join Date
    Jul 2004
    Posts
    148

    Re: URGENT- Asked This Question Twice Already

    Haha, thnx a lot MikeAThon, actually I ended up doing that method Great minds think a like I suppose. I will get a more in-depth look at your code in a bit, but I am still confused as to why you call ClientToScreen and then ScreenToClient, don't the two calls effectively cancel each other out? Thnx

  11. #11
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: URGENT- Asked This Question Twice Already

    Quote Originally Posted by lordkelvan1
    ...but I am still confused as to why you call ClientToScreen and then ScreenToClient, don't the two calls effectively cancel each other out? Thnx
    The calls don't cancel each other because there are different clients. The first call
    Code:
    m_ctlSlider.GetThumbRect( &thumbRect );
    m_ctlSlider.ClientToScreen( &thumbRect );
    converts the rectangle of the thumb (which is currently in client coordinates of the CSliderCtrl) to screen coordinates using the window of m_ctlSlider as a reference. The second call
    Code:
    ScreenToClient( &thumbRect );
    converts the screen coordinates to client coordinates using the CView's window as a reference. The overall result converts the thumb's rectangle from client coordinates of the CSliderCtrl into client coordinates of the CView.

    Mike

  12. #12
    Join Date
    Jul 2004
    Posts
    148

    Re: URGENT- Asked This Question Twice Already

    Ok cool, got it. Although, I don't see much, if any, of a difference when I take out the both calls (I still put them in just to be on the safe side).

  13. #13
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: URGENT- Asked This Question Twice Already

    Quote Originally Posted by lordkelvan1
    Ok cool, got it. Although, I don't see much, if any, of a difference when I take out the both calls (I still put them in just to be on the safe side).
    If you take out the calls, then the lines will be drawn at a position offset by the amount that the CSliderCtrl's are offset in their parent window. The screen-shot below shows this (I took out both calls to make it). You can see the lines are not aligned with the tip of the thumb, but rather are offset by the same amount that the controls are offset in the view.

    If the corners of your controls are coincident with the corners of your view, you won't see any difference, but in the more general case you will.

    Mike
    Attached Images Attached Images  
    Last edited by MikeAThon; August 31st, 2004 at 11:00 PM.

  14. #14
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Fun With Custom Draw

    I couldn't resist a brief foray into custom draw, using CSliderCtrl's

    Regards,
    Mike
    Attached Images Attached Images  

  15. #15
    Join Date
    Jul 2004
    Posts
    148

    Re: URGENT- Asked This Question Twice Already

    Ah, I see what you mean, yes actually I didn't show this (hadn't originally shown it because I didn't think it was relevant), but in my override of OnSize in the cdialogbar class, I actually move the sliderctrl so that it lines up exactly with the beginning of my view So yes, that is why I didn't see any difference. As for the custom draw thing, that is really cool, could you show me how you changed the tip like that (ie. some code possibly ? ).

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured