 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
JD Guest
|
Posted: Sat Apr 29, 2006 11:03 am Post subject: Sizing ListView Column when HScrollPos > 0 |
|
|
Sizing a ListView Column when the Horizontal ScrollPos is
greater than zero exposes a bug with the underlying MS control.
This bug can be readily observed in MS Windows Explorer:
1) Launch Windows Explorer.
2) Size the columns until the Horizontal ScrollBar appears
and has a repectable scrolling range.
3) Scroll to the maximum Horizontal position.
4) Reduce the size of any column and observe.
What you should notice is that instead of the size decreasing
on a pixel per pixel basis as you move the mouse, the size is
decreased exponentially with every pixel move and I haven't
been able to find a solution to the problem.
The sample code has been trimed dowm to the minimum that
demonstrates the problem and it's ready to be cut-n-pasted.
I've isolated the place in the code where the fix needs to be
inserted and moved it to the bottom of the sample where it's
clearly noted in the HeaderMouseMove method. Please keep in
mind that this is just a test-bed so don't be too critical
about other parts of the code.
#include "GradientListView.h"
//--------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
new TGradientListView( this );
}
//--------------------------------------------------------------
//--------------------------------------------------------------
#ifndef GradientListViewH
#define GradientListViewH
//--------------------------------------------------------------
#include <Classes.hpp>
#include <ComCtrls.hpp>
//--------------------------------------------------------------
#ifdef STRICT
#define HEADERWNDPROC WNDPROC
#else
#define HEADERWNDPROC FARPROC
#endif
//--------------------------------------------------------------
typedef BOOL WINAPI (*DLLGRADIENTFILL)( HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG );
//--------------------------------------------------------------
enum THeaderState
{
glvNormal,
glvPressed,
glvHot,
HeaderStateCount
};
//--------------------------------------------------------------
class TGradientListView : public TListView
{
typedef TListView inherited;
protected:
private:
HINSTANCE hMSImg32;
DLLGRADIENTFILL GradientFill;
Graphics::TBitmap *HeaderBmp[ HeaderStateCount ];
TColor FHeaderStartColor, FHeaderEndColor;
void __fastcall GradientFillObject( HDC hDC, TColor StartColor, TColor EndColor, int Width, int Height, unsigned long Mode, int Factor );
void __fastcall AssignRGBToV( TColor Color, TRIVERTEX *V );
int FClickedColumn;
int FHeaderColumn;
bool FMouseInHeader;
bool FHeaderMouseDown;
bool FSizingColumn;
int FSplitterAreaWidth;
TPoint FHeaderClickPoint;
TCursor HeaderCursor;
HWND hHeader;
LONG HeaderWndProcPtr;
HEADERWNDPROC OldHeaderWndProc;
void __fastcall SubclassHeaderWndProc();
void __fastcall HeaderBoundsChanged();
void __fastcall HeaderWndProc( TMessage &Message );
void __fastcall HeaderMouseDown( TMouseButton Button, TShiftState Shift, int X, int Y );
void __fastcall HeaderMouseMove( TShiftState Shift, short X, short Y );
void __fastcall HeaderMouseEnter( TPoint P );
void __fastcall HeaderMouseLeave();
void __fastcall HeaderMouseUp( TMouseButton Button, TShiftState Shift, int X, int Y );
int __fastcall HeaderColumn( TPoint P );
void __fastcall PaintHeaderColumn( int AColumn, THeaderState State );
void __fastcall PaintHeader();
THeaderState __fastcall HeaderColumnState( int Column, TRect ARect );
MESSAGE void __fastcall CMRecreateWnd( TMessage &Message );
MESSAGE void __fastcall WMBoundsChange( TMessage &Message );
public:
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER( CM_RECREATEWND, TMessage, CMRecreateWnd )
VCL_MESSAGE_HANDLER( WM_WINDOWPOSCHANGED, TMessage, WMBoundsChange )
END_MESSAGE_MAP( inherited )
public:
__fastcall TGradientListView( TComponent* Owner );
__fastcall ~TGradientListView();
__published:
};
//--------------------------------------------------------------
#endif
//--------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "GradientListView.h"
#include "shlwapi.h"
//--------------------------------------------------------------
#pragma package(smart_init)
//--------------------------------------------------------------
__fastcall TGradientListView::TGradientListView(TComponent* Owner) : TListView( Owner )
{
Parent = dynamic_cast<TWinControl*>( Owner );
Align = alClient;
ShowColumnHeaders = true;
ViewStyle = vsReport;
TListColumn *pColumn;
for( int x = 0; x < 3; ++x )
{
pColumn = Columns->Add();
pColumn->Caption = "Column " + IntToStr(x);
pColumn->Width = (Width - 20) / 3;
}
TListItem *pItem;
for( int x = 0; x < 3; ++x )
{
pItem = Items->Add();
pItem->Caption = "Col " + IntToStr(0) + " ,Row " + IntToStr(x);
for( int y = 0; y < Columns->Count; ++y )
{
pItem->SubItems->Add("Col " + IntToStr(y+1) + " ,Row " + IntToStr(x));
}
}
HeaderWndProcPtr = reinterpret_cast<LONG>( MakeObjectInstance(HeaderWndProc) );
SubclassHeaderWndProc();
hMSImg32 = ::LoadLibrary( "msimg32.dll" );
if( hMSImg32 ) GradientFill = reinterpret_cast<DLLGRADIENTFILL>( ::GetProcAddress(hMSImg32, "GradientFill") );
for( int x = 0; x < HeaderStateCount; ++x )
{
HeaderBmp[ x ] = NULL;
}
FHeaderStartColor = clWhite;
FHeaderEndColor = clBlack;
FSplitterAreaWidth = 8;
FClickedColumn = -1;
FHeaderColumn = -1;
FMouseInHeader = false;
FHeaderMouseDown = false;
FHeaderClickPoint = Point( -1, -1 );
HeaderCursor = crArrow;
}
//--------------------------------------------------------------
__fastcall TGradientListView::~TGradientListView()
{
if( hMSImg32 ) ::FreeLibrary( hMSImg32 );
for( int x = 0; x < HeaderStateCount; ++x )
{
if( HeaderBmp[x] )
{
delete HeaderBmp[x];
}
}
if( hHeader ) ::SetWindowLong( hHeader, GWL_WNDPROC, reinterpret_cast<LONG>(OldHeaderWndProc) );
FreeObjectInstance( reinterpret_cast<void*>(HeaderWndProcPtr) );
}
//--------------------------------------------------------------
MESSAGE void __fastcall TGradientListView::WMBoundsChange( TMessage &Message )
{
inherited::Dispatch( &Message );
HeaderBoundsChanged();
}
//--------------------------------------------------------------
void __fastcall TGradientListView::HeaderBoundsChanged()
{
for( int x = 0; x < HeaderStateCount; ++x )
{
if( !HeaderBmp[x] )
{
HeaderBmp[x] = new Graphics::TBitmap();
HeaderBmp[x]->PixelFormat = pf32bit;
HeaderBmp[x]->Canvas->Brush->Style = bsClear; // Reported to speed-up bitmap operations
}
}
int w = 0; for( int x = 0; x < Columns->Count; ++x ) w += Columns->Items[x]->Width;
if( w < ClientWidth ) w = ClientWidth;
if( (HeaderBmp[0]->Width < w) || (HeaderBmp[0]->Width > (w - 10)) )
{
TRect R;
::GetWindowRect( ListView_GetHeader(Handle), &R );
for( int x = 0; x < HeaderStateCount; ++x )
{
HeaderBmp[x]->Width = w;
HeaderBmp[x]->Height = R.Bottom - R.Top;
switch( x )
{
case glvHot: GradientFillObject( HeaderBmp[x]->Canvas->Handle, FHeaderStartColor, FHeaderEndColor, HeaderBmp[x]->Width, HeaderBmp[x]->Height, GRADIENT_FILL_RECT_V, 4 ); break;
case glvNormal: GradientFillObject( HeaderBmp[x]->Canvas->Handle, FHeaderStartColor, FHeaderEndColor, HeaderBmp[x]->Width, HeaderBmp[x]->Height, GRADIENT_FILL_RECT_V, 2 ); break;
case glvPressed: GradientFillObject( HeaderBmp[x]->Canvas->Handle, FHeaderEndColor, FHeaderStartColor, HeaderBmp[x]->Width, HeaderBmp[x]->Height, GRADIENT_FILL_RECT_V, 1 ); break;
}
}
}
}
//--------------------------------------------------------------
void __fastcall TGradientListView::GradientFillObject( HDC hDC, TColor StartColor, TColor EndColor, int Width, int Height, unsigned long Mode, int Factor )
{
void *pMesh;
int NumberOfVertices, FFactor;
TRIVERTEX Vertices[3];
GRADIENT_RECT GradientRect;
GRADIENT_TRIANGLE GradientTriangle;
memset( &Vertices, 0, sizeof(TRIVERTEX) * 3 );
AssignRGBToV( StartColor, &Vertices[0] );
AssignRGBToV( EndColor, &Vertices[1] );
if( Mode == GRADIENT_FILL_TRIANGLE )
{
Vertices[ 2 ] = Vertices[ 1 ];
Vertices[ 1 ].y = (Height - 1) * Factor * 2;
Vertices[ 2 ].x = (Width - 1) * Factor * 2;
GradientTriangle.Vertex1 = 0;
GradientTriangle.Vertex2 = 1;
GradientTriangle.Vertex3 = 2;
pMesh = &GradientTriangle;
NumberOfVertices = 3;
}
else
{
Vertices[ 1 ].x = (Width - 1) * Factor;
Vertices[ 1 ].y = (Height - 1) * Factor;
GradientRect.UpperLeft = 0;
GradientRect.LowerRight = 1;
pMesh = &GradientRect;
NumberOfVertices = 2;
}
GradientFill( hDC, (TRIVERTEX*)&Vertices, NumberOfVertices, pMesh, 1, Mode );
}
//--------------------------------------------------------------
void __fastcall TGradientListView::AssignRGBToV( TColor Color, TRIVERTEX *V )
{
int C = ColorToRGB( Color );
V->Red = ( GetRValue(C) << 8 );
V->Green = ( GetGValue(C) << 8 );
V->Blue = ( GetBValue(C) << 8 );
}
//--------------------------------------------------------------
MESSAGE void __fastcall TGradientListView::CMRecreateWnd( TMessage &Message )
{
inherited::Dispatch( &Message );
SubclassHeaderWndProc();
}
//--------------------------------------------------------------
void __fastcall TGradientListView::SubclassHeaderWndProc()
{
hHeader = ListView_GetHeader( Handle );
if( hHeader ) OldHeaderWndProc = reinterpret_cast<HEADERWNDPROC>( ::SetWindowLong(hHeader, GWL_WNDPROC, HeaderWndProcPtr) );
}
//--------------------------------------------------------------
void __fastcall TGradientListView::HeaderWndProc( TMessage &Message )
{
switch( Message.Msg )
{
case WM_PAINT: if( ::GetUpdateRect(hHeader, NULL, false) )
{
PaintHeader();
Message.Result = 0;
}
break;
case WM_ERASEBKGND: Message.Result = -1; break;
case WM_LBUTTONDOWN: HeaderMouseDown( mbLeft, KeysToShiftState(Message.WParam), Message.LParamLo, Message.LParamHi ); Message.Result = 0; break;
case WM_MOUSEMOVE: HeaderMouseMove( KeysToShiftState(Message.WParam), LOWORD(Message.LParam), HIWORD(Message.LParam) ); Message.Result = 0; break;
case WM_MOUSELEAVE: HeaderMouseLeave(); break;
case WM_LBUTTONUP: HeaderMouseUp( mbLeft, KeysToShiftState(Message.WParam), LOWORD(Message.LParam), HIWORD(Message.LParam) ); Message.Result = 0; break;
case WM_SETCURSOR: ::SetCursor( CopyCursor(Screen->Cursors[HeaderCursor]) ); Message.Result = 0; break;
case WM_DESTROY: Message.Result = ::CallWindowProc(OldHeaderWndProc, hHeader, Message.Msg, Message.WParam, Message.LParam );
::SetWindowLong( hHeader, GWL_WNDPROC, reinterpret_cast<LONG>(OldHeaderWndProc) );
hHeader = NULL;
OldHeaderWndProc = NULL;
break;
default: Message.Result = ::CallWindowProc( OldHeaderWndProc, hHeader, Message.Msg, Message.WParam, Message.LParam );
}
}
//--------------------------------------------------------------
void __fastcall TGradientListView::HeaderMouseDown( TMouseButton Button, TShiftState Shift, int X, int Y )
{
FClickedColumn = -1;
FSizingColumn = false;
if( Button == mbLeft )
{
::SetCapture( hHeader );
if( FHeaderColumn > -1 )
{
if( HeaderCursor == crHSplit ) FSizingColumn = true;
else PaintHeaderColumn( FHeaderColumn, glvPressed );
}
FClickedColumn = FHeaderColumn;
FHeaderClickPoint = Point( X, Y );
FHeaderMouseDown = true;
}
}
//--------------------------------------------------------------
void __fastcall TGradientListView::HeaderMouseEnter( TPoint P )
{
FHeaderColumn = HeaderColumn( P );
if( FHeaderColumn > -1 )
{
if( FHeaderMouseDown && FHeaderColumn == FClickedColumn && HeaderCursor == crArrow ) PaintHeaderColumn( FHeaderColumn, glvPressed );
else PaintHeaderColumn( FHeaderColumn, glvHot );
}
FMouseInHeader = true;
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof( TRACKMOUSEEVENT );
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hHeader;
TrackMouseEvent( &tme );
}
//--------------------------------------------------------------
void __fastcall TGradientListView::HeaderMouseLeave()
{
if( FHeaderColumn > -1 ) PaintHeaderColumn( FHeaderColumn, glvNormal );
FMouseInHeader = false;
FHeaderColumn = -1;
}
//--------------------------------------------------------------
void __fastcall TGradientListView::HeaderMouseUp( TMouseButton Button, TShiftState Shift, int X, int Y )
{
if( Button == mbLeft )
{
::ReleaseCapture();
if( FHeaderColumn > -1 )
{
int AColumn = HeaderColumn( Point(X,Y) );
if( AColumn != FHeaderColumn ) PaintHeaderColumn( FHeaderColumn, glvNormal );
else PaintHeaderColumn( FHeaderColumn, glvHot );
if( FHeaderColumn > -1 && FHeaderColumn == FClickedColumn && !FSizingColumn )
{
ShowMessage("Column Header Click " + IntToStr(FHeaderColumn) );
}
FHeaderColumn = AColumn;
}
}
FHeaderMouseDown = false;
FClickedColumn = -1;
FSizingColumn = false;
FHeaderClickPoint = Point( -1, -1 );
}
//--------------------------------------------------------------
int __fastcall TGradientListView::HeaderColumn( TPoint P )
{
TRect R;
HeaderCursor = crArrow;
for( int AColumn = 0; AColumn < Columns->Count; ++AColumn )
{
::SendMessage( hHeader, HDM_GETITEMRECT, (WPARAM)AColumn, (LPARAM)&R );
if( PtInRect(R,P) )
{
if( AColumn > 0 && Columns->Items[AColumn - 1]->Width == 0 )
{
R.right = R.left + FSplitterAreaWidth;
if( PtInRect(R,P) )
{
HeaderCursor = crHSplit;
return AColumn - 1;
}
}
else
{
R.left = R.right - FSplitterAreaWidth;
if( PtInRect(R,P) ) HeaderCursor = crHSplit;
}
return AColumn;
}
}
if( Columns->Items[Columns->Count - 1]->Width == 0 )
{
R.right = R.left + FSplitterAreaWidth;
if( PtInRect(R,P) )
{
HeaderCursor = crHSplit;
return Columns->Count - 1;
}
}
return -1;
}
//--------------------------------------------------------------
THeaderState __fastcall TGradientListView::HeaderColumnState( int AColumn, TRect ARect )
{
TPoint P;
::GetCursorPos( &P );
::ScreenToClient( hHeader, &P );
if( HeaderCursor == crHSplit )
if( AColumn == FHeaderColumn ) return glvHot;
else return glvNormal;
else if( FHeaderMouseDown )
if( FClickedColumn == AColumn )
if( PtInRect(ARect,P) ) return glvPressed;
else return glvNormal;
else return glvNormal;
else if( PtInRect(ARect,P) ) return glvHot;
else return glvNormal;
}
//--------------------------------------------------------------
void __fastcall TGradientListView::PaintHeaderColumn( int AColumn, THeaderState State )
{
TRect R;
HDC hDC = ::GetDC( hHeader );
TCanvas *pCanvas = new TCanvas;
pCanvas->Handle = hDC;
if( AColumn < 0 )
{
::SendMessage( hHeader, HDM_GETITEMRECT, (WPARAM)(Columns->Count - 1), (LPARAM)&R );
R.left = R.right;
R.Right = ClientWidth;
}
else ::SendMessage( hHeader, HDM_GETITEMRECT, (WPARAM)AColumn, (LPARAM)&R );
pCanvas->CopyRect( R, HeaderBmp[State]->Canvas, R );
--R.bottom;
switch( State )
{
case glvHot: Frame3D( pCanvas, R, FHeaderStartColor, FHeaderEndColor, 1 ); break;
case glvNormal: Frame3D( pCanvas, R, FHeaderStartColor, FHeaderEndColor, 1 ); break;
case glvPressed: Frame3D( pCanvas, R, FHeaderEndColor, FHeaderStartColor, 1 ); break;
}
if( AColumn > -1 )
{
R.left += 5;
int PreviouseMode = ::SetBkMode( pCanvas->Handle, TRANSPARENT );
::DrawText( pCanvas->Handle, Columns->Items[AColumn]->Caption.c_str(), -1, &R, DT_SINGLELINE | DT_VCENTER | DT_LEFT );
::SetBkMode( pCanvas->Handle, PreviouseMode );
}
::ReleaseDC( hHeader, hDC );
pCanvas->Handle = NULL;
delete pCanvas;
}
//--------------------------------------------------------------
void __fastcall TGradientListView::PaintHeader()
{
TRect R, R1;
PAINTSTRUCT ps = { 0 };
::BeginPaint( hHeader, &ps );
::ValidateRect( hHeader, &ps.rcPaint );
for( int AColumn = 0; AColumn < Columns->Count; ++AColumn )
{
::SendMessage( hHeader, HDM_GETITEMRECT, (WPARAM)AColumn, (LPARAM)&R );
::IntersectRect( &R1, &ps.rcPaint, &R );
if( !::IsRectEmpty(&R1) ) PaintHeaderColumn( AColumn, HeaderColumnState(AColumn, R) );
}
R.left = R.right;
R.right = ClientWidth;
IntersectRect( &R1, &ps.rcPaint, &R );
if( !IsRectEmpty(&R1) ) PaintHeaderColumn( -1, glvNormal );
::EndPaint( hHeader, &ps );
}
//--------------------------------------------------------------
void __fastcall TGradientListView::HeaderMouseMove( TShiftState Shift, short X, short Y )
{
if( !FMouseInHeader ) HeaderMouseEnter( Point(X,Y) );
else if( !FSizingColumn )
{
int AColumn = HeaderColumn( Point(X,Y) );
if( AColumn != FHeaderColumn )
{
if( FHeaderColumn > -1 ) PaintHeaderColumn( FHeaderColumn, glvNormal );
if( AColumn > -1 )
{
if( AColumn == FClickedColumn ) PaintHeaderColumn( AColumn, glvPressed );
else if( FHeaderMouseDown ) PaintHeaderColumn( AColumn, glvNormal );
else PaintHeaderColumn( AColumn, glvHot );
}
}
FHeaderColumn = AColumn;
}
else
{
if( FHeaderClickPoint.x < X )
{
Columns->Items[FClickedColumn]->Width = Columns->Items[FClickedColumn]->Width + (X - FHeaderClickPoint.x);
FHeaderClickPoint = Point( X, Y );
}
else if( Columns->Items[FClickedColumn]->Width > 0 )
{
if( Columns->Items[FClickedColumn]->Width > (FHeaderClickPoint.x - X) )
{
Columns->Items[FClickedColumn]->Width = Columns->Items[FClickedColumn]->Width - (FHeaderClickPoint.x - X);
//*******************************
//
// Start of problem block
//
//*******************************
SCROLLINFO si = { 0 };
si.cbSize = sizeof( SCROLLINFO );
si.fMask = SIF_POS;
::GetScrollInfo(Handle, SB_HORZ, &si);
if( si.nPos > 0 )
{
// solution goes here
}
else
{
FHeaderClickPoint = Point( X, Y );
}
//*******************************
//
// end of problem block
//
//*******************************
}
else
{
FHeaderClickPoint.x -= Columns->Items[FClickedColumn]->Width;
Columns->Items[FClickedColumn]->Width = 0;
}
}
HeaderBoundsChanged();
}
}
//--------------------------------------------------------------
~ JD |
|
| Back to top |
|
 |
Bob Gonder Guest
|
Posted: Sat Apr 29, 2006 4:03 pm Post subject: Re: Sizing ListView Column when HScrollPos > 0 |
|
|
JD wrote:
| Quote: | What you should notice is that instead of the size decreasing
on a pixel per pixel basis as you move the mouse, the size is
decreased exponentially with every pixel move and I haven't
been able to find a solution to the problem.
|
I'm not sure it's a bug, more like a "feature".
What I observe is this.
If you move a bar one pixel left, and hold the mouse still, the
listbox continues to shrink at a steady (slow) pace until the sub-box
(column) is minimized.
As the box gets smaller, and is maxed to the right, the invisible left
side moves right. This moves the sub-box one pixel right, but the
mouse is still one pixel left of the bar, so it shrinks the box
another pixel, which moves the box right one pixel.......
If you continue to move the mouse left steady pace, one pixel per box
draw, first, it's one pixel left, then box is one right, then mouse is
2 left, so box moves another 2, then mouse is 3 so box moves a further
3. So in screen terms, mouse is moving steady pace, but box is
accelerating.
I'd leave it alone, but if it really bothers you, I see 2 ways to go
about fixing it.
1) limit mouse movement to 1 or 2 pixels (limits shrinking to one or
two pixel speed)
2) reset mouse to bar. If mouse moves faster, box shrinks faster. If
mouse stops, box stops.
Both of these might be disconcerting as the mouse would appear to
freeze.
Third option would be to somehow remember last mouse position, and
only reduce the box by the delta rather than the absolute. |
|
| Back to top |
|
 |
JD Guest
|
Posted: Sat Apr 29, 2006 6:03 pm Post subject: Re: Sizing ListView Column when HScrollPos > 0 |
|
|
Bob Gonder <notbg (AT) notmindspring (DOT) invalid> wrote:
| Quote: |
What I observe is this. [...]
|
I saw the same but hadn't noticed that behavior until I tested
it with Windows Explorer.
| Quote: | I'd leave it alone,
|
I don't think that I can because when running my code, even
though it behaves the same, it's much more dramatic because
I've optimized the drawing to eliminate flickering. Even worse,
If the scrolled area is large enough, it will collapse a column
entirely in the blink of an eye.
| Quote: | limit mouse movement to 1 or 2 pixels (limits shrinking to
one or two pixel speed)
|
This isn't possible. I logged the messages and there getting
processed on a per pixel basis. Sure there were a couple that
slipped through that were multiple pixels but they required
effort on my part to effect them.
| Quote: | reset mouse to bar. If mouse moves faster, box shrinks
faster. If mouse stops, box stops.
|
At this point, I'm thinking that the mouse is going to have to
be repositioned but I *really* don't wanna do that.
| Quote: | Third option would be to somehow remember last mouse
position, and only reduce the box by the delta rather than
the absolute.
|
I'm not sure what you mean by this. The code currently saves
the click point, makes the size change and then updates the
click point to the current point. The change in size is
calculated by comparing the click point to the current point.
What the ultimate problem is that when the column size changes,
the scrollbar is affected which causes a redraw because the
window is no longer scrolled to that position.
If the mouse it at 100 and moved to 99, after that one pixel
move has been processed and the window is redrawn, the mouse
is now at 98 even though it wasn't moved! (your observations
seem to confirm this).
I'm hoping that it's just a not-so-simple logic problem that
another pair of eyes can see.
~ JD |
|
| Back to top |
|
 |
Bob Gonder Guest
|
Posted: Sat Apr 29, 2006 10:03 pm Post subject: Re: Sizing ListView Column when HScrollPos > 0 |
|
|
JD wrote:
| Quote: | Third option would be to somehow remember last mouse
position, and only reduce the box by the delta rather than
the absolute.
I'm not sure what you mean by this. The code currently saves
the click point, makes the size change and then updates the
click point to the current point. The change in size is
calculated by comparing the click point to the current point.
|
Well, what I saw was if the mouse is one pixel left of bar, box
collapses at one pixel speed (constant). To mimic normal (non-maxed
scroll bar), moving mouse left at constant speed, to move box right at
constant speed, means instead of taking absolute difference from bar
to mouse for the speed, take difference in movement from last draw to
this, as speed.
Now, that sounds a lot like what you are saying it is doing.
So, the question is...what coordinate system is it using?
If it is measuring mouse position from left-most (hidden box) edge,
then you would still see larger movement than the absolute
screen-coordinate movement.
| Quote: | If the mouse it at 100 and moved to 99, after that one pixel
move has been processed and the window is redrawn, the mouse
is now at 98 even though it wasn't moved!
|
Which would indicate that you are reading client (box) coordinates at
a time when you really want to know the real-world (screen)
coordinates. There _are_ conversion routines somewhere in the api..... |
|
| Back to top |
|
 |
JD Guest
|
Posted: Sun Apr 30, 2006 3:03 pm Post subject: Re: Sizing ListView Column when HScrollPos > 0 |
|
|
Bob Gonder <notbg (AT) notmindspring (DOT) invalid> wrote:
| Quote: |
If the mouse it at 100 and moved to 99, after that one pixel
move has been processed and the window is redrawn, the mouse
is now at 98 even though it wasn't moved!
Which would indicate that you are reading client (box)
coordinates at a time when you really want to know the real-
world (screen) coordinates.
|
Using client relative v/s screen relative makes no difference
because the difference between the old position and the new
position is the same regardless of what variables are used to
calculate it.
Now, I do realize that in the above example, after the column
is resized, if I were to look at the mouse position in screen
relative terms, I wouldn't see that extra change but that's not
the problem. I used that example to illustrate that the scroll
position had changed which is the problem because it relocates
the header on screen. I can get the desired sizing effect but
it leaves the crHSplit mouse *way* out of position.
At the moment, I'm freezing the mouse at the screen relative
click point until the scroll position reaches zero and it works
but I don't like it.
~ JD |
|
| Back to top |
|
 |
Bob Gonder Guest
|
Posted: Sun Apr 30, 2006 5:03 pm Post subject: Re: Sizing ListView Column when HScrollPos > 0 |
|
|
JD wrote:
| Quote: | Using client relative v/s screen relative makes no difference
because the difference between the old position and the new
position is the same regardless of what variables are used to
calculate it.
|
Um, but not if it is using box-relative.
As you move the bar left, the box moves right.
Let's run some numbers.
Listbox is scrolled right to max by 50 pixels.
Seperator bar is at 100 in the client window (150 listbox-relative)
Seperator bar remains stationary.
Left half of table is message info, right half is after application of
message.
Event box at mouse at Delta box goes to mouse at
Click -50 100 (150r) 0 -50 [150r]
Drag -50 99 (149r) 1 -49 [148r]
Hold -49 99 (148r) 1 -48 [147r]
Hold -48 99 (147r) 1 -47 [146r]
Drag -47 98 (145r) 2 -45 [143r]
Drag -45 97 (142r) 3 -42 [139r]
Drag -42 96 (138r) 4 -38 [134r]
Drag -38 95 (133r) 5 -33 [128r]
Hold -33 95 (128r) 5 -28 [123r]
The problem you are trying to solve is the large delta.
You want it to be 0 or 1 in all these instances.
Look at the move in the last line.
If you remember the screen coordinate of 95, you would see 0 movement.
If OTOH, you remember the box-relative 133, and now you see
box-relative 128, you see a movement of 5.
Since you are processing WM_MOUSEMOVE, the mouse coordinates are in
listbox-relative coordinates (the fast-changing ones).
You might try remembering/comparing ClientToScreen(msg point) values.
Or, remember the mouse position _after_ the resize with
GetCurrentPos() and ScreenToClient(),, and compare directly to the
next message.
I'm thinking the first method (ClientToScreen) would work in all
cases, right, left, maxed or not? |
|
| Back to top |
|
 |
JD Guest
|
Posted: Mon May 01, 2006 3:03 pm Post subject: Re: Sizing ListView Column when HScrollPos > 0 |
|
|
Bob Gonder <notbg (AT) notmindspring (DOT) invalid> wrote:
| Quote: |
Let's run some numbers. [...]
|
I understand what you're saying and agree with you except for
the problem with the mouse progressively moving away from the
right limit of the header column. I'm just trading one problem
for another and it seems that the only solution to both is to
pin the mouse to the right boundry.
Thanks for taking the time.
~ JD |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|