I have gone through all I could find on net but seems like I am missing some very basic thing, having spent so much time on this problem isn't making things easier, so I will go ahead and ask for a help here, see if you can find what I am doing wrong.
Here is the code :
jControl.h
#ifndef _JCONTROL_H
#define _JCONTROL_H
namespace view
{
class jControl
{
public:
HWND hwnd;
HWND hParent;
HBITMAP hbitmap;
std::string text;
HFONT hFont;
COLORREF textColor;
COLORREF backgroundColor;
RECT updateRegion;
bool isUpdateRegion;
public:
jControl ( );
jControl ( HWND parent, HINSTANCE hInstance, WORD bitmap );
~jControl ( );
virtual void show ( );
virtual void hide ( );
virtual void disable ( );
virtual void enable ( );
virtual std::string getText ( );
virtual void setText ( std::string txt );
virtual void setUpdateRegion ( RECT rect );
virtual void setTextColor ( COLORREF crf );
virtual void setBackgroundColor ( COLORREF crf );
virtual void setFont ( HFONT font );
virtual bool setRange ( int range );
virtual bool setStep ( int step );
};
};
#endif
jControl.cpp
#include "jControl.h"
namespace view
{
jControl::jControl( ){};
jControl::jControl ( HWND parent, HINSTANCE hInstance, WORD bitmap )
: hParent ( parent ), hbitmap ( NULL ), isUpdateRegion ( false ), textColor ( RGB ( 255, 255, 255 ) ), backgroundColor ( RGB ( 54, 54, 54 ) )
{
hFont = ::CreateFont ( 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Myriad Pro" );
if ( bitmap != 0 ) hbitmap = LoadBitmap ( hInstance, MAKEINTRESOURCE ( bitmap ) );
};
jControl::~jControl ( )
{
if ( hbitmap ) DeleteObject ( hbitmap );
if ( hFont ) DeleteObject ( hFont );
if ( hwnd ) DestroyWindow ( hwnd );
};
void jControl::show( ) { ::ShowWindow( hwnd, SW_SHOW ); };
void jControl::hide( ) { ::ShowWindow( hwnd, SW_HIDE ); };
void jControl::disable ( ) { EnableWindow ( hwnd, false ); };
void jControl::enable ( ) { EnableWindow ( hwnd, true ); };
std::string jControl::getText ( ) { return text; };
void jControl::setText ( std::string txt ) { text = txt; InvalidateRect ( hwnd, NULL, true ); };
void jControl::setUpdateRegion ( RECT rect ) { updateRegion = rect; isUpdateRegion = true; };
void jControl::setTextColor ( COLORREF crf ) { textColor = crf; };
void jControl::setBackgroundColor ( COLORREF crf ) { backgroundColor = crf; ::InvalidateRect ( hwnd, NULL, true ); };
void jControl::setFont ( HFONT font ) { hFont = font; };
bool jControl::setRange ( int range ) { return true; };
bool jControl::setStep ( int step ) { return true; };
};
jProgressBar.h
#ifndef _JPROGRESSBAR_H
#define _JPROGRESSBAR_H
/** * Parent class include */
#ifndef _JCONTROL_H
#include "../jControl/jControl.h"
#endif
namespace view
{
class jProgressBar : public jControl
{
public:
jProgressBar ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap );
~jProgressBar ( );
std::string getText ( );
void setText ( std::string txt );
bool setRange ( int range );
bool setStep ( int step );
};
};
#endif
jProgressBar.cpp
#include "jProgressBar.h"
namespace view
{
jProgressBar::jProgressBar( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jControl( parent, hInstance, bitmap )
{
hwnd = CreateWindowEx ( WS_EX_TOPMOST, PROGRESS_CLASS, txt.c_str(), WS_CHILD | WS_CLIPSIBLINGS | WS_CHILD, x, y, width, height, parent, 0, hInstance, 0 );
};
jProgressBar::~jProgressBar ( ){};
bool jProgressBar::setRange ( int range )
{
if ( SendMessage ( hwnd, PBM_SETRANGE, 0, MAKELPARAM ( 0, range ) ) != 0 ) return true;
return false;
};
bool jProgressBar::setStep ( int step )
{
if ( SendMessage ( hwnd, PBM_SETSTEP, ( WPARAM ) step, 0 ) != 0 ) return true;
return false;
};
};
And here is the error :
[Linker error] jProgressBar/jProgressBar.cpp:14: undefined reference to `vtable for view::jProgressBar'
I get the error on Constructor and Destructor of JProgressBar.
The problem may be in these lines:
std::string getText( );
and
void setText( std::string txt );
in jProgressBar.h
Please provide a definition for this function in Cpp or remove it from header, I think it should compile. The main reason is: you have overridden a virtual function in a child class with a declaration, but haven't given a definition for the method.
The compiler knows about the function, but the linker is not able to find the definition
For example:
class Base
{
virtual void f() = 0;
}
class Derived : public Base
{
void f();
}
Related
I'm trying to use DeferWindowPos to update the z order of some dialog boxes, but it's not working. Well, the z order does change, but not always in the requested order. Why could that be? It's supposed to work, right?
I am checking all the return values. I observered that if I add the flag SWP_NOSENDCHANGING, DeferWindowPos returns 0 without GetLastError() returning any error code. I didn't add message handlers for WM_WINDOWPOSCHANGING in any of my dialog classes.
For now I use SetWindowPos instead. It always works but it's slower.
I wrote a test, see code below. Any help would be much appreciated.
void test()
{
#ifdef DEFER_WINDOW_POS
class DeferPos
{
public:
DeferPos( const int innWindowCount = 1 )
{
m_hdwp = BeginDeferWindowPos( innWindowCount );
assert( m_hdwp != nullptr );
}
~DeferPos()
{
if( !EndDeferWindowPos(m_hdwp) ) { assert( false ); }
}
void Set( HWND hWnd, HWND hWndAfter, int x, int y, int nWidth, int nHeight, UINT uFlags )
{
assert( m_hdwp != nullptr );
assert( GetLastError() == 0 );
m_hdwp = DeferWindowPos( m_hdwp, hWnd, hWndAfter, x, y, nWidth, nHeight, uFlags );
assert( m_hdwp != nullptr );
assert( GetLastError() == 0 );
}
private:
HDWP m_hdwp = nullptr;
};
auto update_z_order = [](const std::vector<HWND>& vec, UINT flags)
{
DeferPos dp( static_cast<int>(vec.size()) );
HWND hWndAfter = HWND_TOP;
for( HWND hWnd : vec )
{
dp.Set( hWnd, hWndAfter, 0, 0, 0, 0, flags );
hWndAfter = hWnd;
}
};
#else
auto update_z_order = [](const std::vector<HWND>& vec, UINT flags)
{
HWND hWndAfter = HWND_TOP;
for( HWND hWnd : vec )
{
::SetWindowPos(hWnd, hWndAfter, 0, 0, 0, 0, flags );
hWndAfter = hWnd;
}
};
#endif
auto get_dialog_z_order = []()
{
std::vector<HWND> vec;
EnumWindows( [](HWND hWnd, LPARAM lparam)-> BOOL
{
if( dynamic_cast<CDialog*>(CWnd::FromHandle(hWnd)) )
{
reinterpret_cast<std::vector<HWND>*>(lparam)->push_back( hWnd );
}
return TRUE;
}, reinterpret_cast<LPARAM>(&vec) );
return vec;
};
const std::vector<HWND> original_order = get_dialog_z_order();
const std::vector<HWND> reverse_order( original_order.rbegin(), original_order.rend() );
const UINT flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE;
update_z_order( reverse_order, flags );
const std::vector<HWND> new_order = get_dialog_z_order();
assert( new_order == reverse_order ); // this assert sometimes fails when DEFER_WINDOW_POS is defined
}
I am porting 32-bit code to 64-bit code in VS2010. My application is crashing when trying to lauch one of the dialog box but I found it works perfectly in 32-bit configuration but not in 64-bit. I found there is an array of objects which is containing array of characters, there data is not proper in 64-bit platform. eg. Suppose there is a list of strings: red, black,....In 32-bit, list is displayed correctly but in 64-bit 2nd object's character pointer points to k of Black i.e 4 bytes ahead of actual data. Object size is 144 bytes in 32-bit platform but in 64-bit it's 148 bytes for each object.
BOOL SomeDlg::OnInitDialog( HWND hwnd, HWND hwndFocus, LPARAM lParam )
{
MEMBERASSERT();
CABCDialog::OnInitDialog( hwnd, hwndFocus, lParam );
int nHeight = ListBox_GetItemHeight( GetDlgItem(hwnd, IDC_DUMMYLIST), -1 );
m_myLst.SetItemHeight(-1, nHeight);
m_ClrLst.SetItemHeight(-1, nHeight);
char smyItem[64];
for (UINT i=0; i < 10; i++)
{
LoadString(g_hInstance, IDS_COLORNAMES+i, smyItem, ELEMENTS_IN(smyItem));
m_ZAItems[i].SetColor(m_pSettings->m_rgbColors[i]);
m_ZAItems[i].SetText(smyItem);
//debug issue, check size of object
int a = sizeof(m_ZAItems[i]);
m_myLst.AddItem( &m_ZAItems[i] );
}
//some other stuff
}
class SomeDlg : public CABCDialog
{
private:
MyDrwaLstBox m_myLst;
My_ColorComboBox m_ClrLst;
My_ColorText m_ZAItems[11];
private:
SomeDlg();
SomeDlg(const SomeDlg &);
const SomeDlg &operator=(const SomeDlg &);
public:
SomeDlg(HWND hwndZW, MCURRENT* pSettings , LPCSTR szName );
virtual void Notification( ADM_Wnd *pWnd, UINT uID, int nNotificationCode, LPARAM lData );
virtual BOOL OnInitDialog( HWND hwnd, HWND hwndFocus, LPARAM lParam );
};
class MyDrwaLstBox : public MY_ListBox
{
protected:
BOOL m_bpmn;
private:
MyDrwaLstBox( const MyDrwaLstBox& );
const MyDrwaLstBox & operator=( const MyDrwaLstBox & );
public:
MyDrwaLstBox ();
virtual void OnDrawItem( HWND hwnd,
const DRAWITEMSTRUCT * lpDrawItem );
};
class My_ColorText : public My_Color
{
private:
enum { txtLen = 128 };
TCHAR m_szText[ txtLen ];
My_ColorText ( const My_ColorText & );
const My_ColorText &operator=( const My_ColorText & );
public:
My_ColorText ();
My_ColorText ( COLORREF rgbColor, LPCTSTR pszText );
void SetText( LPCTSTR pszText );
void SetText( HINSTANCE hInstance, UINT uID );
LPCTSTR GetText();
virtual void Draw( HDC hDC, RECT rRect, BOOL bChecked, BOOL bDisabled,
BOOL bFocus, BOOL bGrayed, BOOL bSelected );
};
My_ColorText::My_ColorText()
{
m_szText[0] = '\0';
}
My_ColorText::My_ColorText( COLORREF rgbColor, LPCTSTR pszText )
: My_Color( rgbColor )
{
MDC_strncpyz( m_szText, pszText );
}
void My_ColorTex::SetText( LPCTSTR pszText )
{
MDC_strncpyz( m_szText, pszText );
}
void My_ColorText::SetText( HINSTANCE hInstance, UINT uID )
{
*m_szText = '\0';
LoadString( hInstance, uID, m_szText, ELEMENTS_IN( m_szText ) );
}
LPCTSTR My_ColorText::GetText()
{
return m_szText;
}
template <size_t size>
LPSTR MDC_strncpyz(CHAR (&dest)[size], LPCSTR srce) { return MDC_strncpyz(dest, srce, size); }
class My_Color : public My_DrawItem
{
private:
COLORREF m_rgbColor;
private:
My_Color( const My_Color & );
const My_Color & operator=( const My_Color & );
public:
My_Color( void );
My_Color( COLORREF rgbColor );
virtual void Draw( HDC hDC,
RECT rRect,
BOOL bChecked,
BOOL bDisabled,
BOOL bFocus,
BOOL bGrayed,
BOOL bSelected );
};
My_Color::My_Color void )
: m_rgbColor( RGB_BLACK )
{
}
My_Color::My_Color( COLORREF rgbColor )
: m_rgbColor( rgbColor )
{
}
class My_DrawItem
{
protected:
BOOL m_bInListBox;
DWORD m_dwUser;
private:
My_DrawItem( const My_DrawItem & );
const My_DrawItem & operator=( const My_DrawItem & );
public:
My_DrawItem();
virtual ~My_DrawItem();
virtual void Draw( HDC hDC,
RECT rRect,
BOOL bChecked,
BOOL bDisabled,
BOOL bFocus,
BOOL bGrayed,
BOOL bSelected );
};
My_DrawItem::My_DrawItem()
: m_bInListBox( FALSE ),
m_dwUser( 0 )
{
}
'SomeDlg' class contains object of My_ColorComboBox class which in turn contains array of object of class My_ColorText.
when contructor of My_ColorText class gets called through My_ColorComboBox class then difference of base addresses of m_ColorItems[0]'s m_szText and m_ColorItems[1]'s m_szText is equal to 152 bytes. Means My_ColorText() constructor assigns base address for m_szText variable at the differnce of 152 bytes.
But When contructor of My_ColorText class gest called through SomeDlg class then difference of base addresses of m_ZAItems[0]'s m_szText and m_ZAItems[1]'s m_szText is equal to 148 bytes. Hence strings are not getting inserted at proper location of difference of 152 bytes.
When I check sizeof(My_ColorText), in both cases it gives me 152 bytes.
I have created objects on heap instead of creating on stack.
Below lines have added to solve the problem.
for (UINT i=0; i < 10; i++)
{
LoadString(g_hInstance, IDS_COLORNAMES+i, smyItem, ELEMENTS_IN(smyItem));
//m_ZAItems[i].SetColor(m_pSettings->m_rgbColors[i]);
//m_ZAItems[i].SetText(smyItem);
myLst.AddItem( new My_ColorText( m_pSettings->m_rgbColors[i], smyItem ) );
}
EDIT : Now this is strange, if I move the call to jItems::populate ( std::string myList ) to the constructor of jDropDown::jDropDown from else where in the jDropDown::jDropDown, the child windows get created.
Originally its been called when the dropdown(jDropDown) window is made visible(shown), and the flow of the program doesn't allow a call to jItems::populate ( std::string myList ) be moved to constructor of jDropDown::jDropDown.
What I an trying to do is create a custom Dropdown box from scratch, the problem I am facing is the final Items(jItem) windows are not created, its an oop design and
every Items(jItem) is derived from jPanel, the other parts of the dropdown box are also drived from jPanel so creating each and every window follows the same process yet the final
Items(jItem) windows are not created, they are not visible and I can't find them with visual studio Spy++
I have checked for instance handle and window handle, and both the checks returns true, yet the jItem windows are not visible and can't find them in spy++ (I can see all the other windows in spy++)
Any help is appreciated.
Here is a reference image and some relevant code.
bool jPanel::registered = false;
jPanel::jPanel( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap, DWORD style )
: jControl( parent, hInstance, bitmap )
{
if ( ! registered )
{
WNDCLASSEX wincl;
wincl.hInstance = hInstance;
wincl.lpszClassName = "jPanel";
wincl.lpfnWndProc = WndProc;
wincl.style = CS_BYTEALIGNWINDOW;
wincl.cbSize = sizeof ( WNDCLASSEX );
wincl.hIcon = 0;
wincl.hIconSm = 0;
wincl.hCursor = ::LoadCursor ( NULL, IDC_ARROW );
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 4;
wincl.hbrBackground = ::CreateSolidBrush ( backgroundColor );
::RegisterClassEx ( &wincl );
jPanel::registered = true;
}
DWORD flag = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD;
if ( style ) flag = flag | style;
hwnd = ::CreateWindowEx ( 0, "jPanel", txt.c_str ( ), flag, x, y, width, height, parent, 0, hInstance, ( LPVOID ) this ) ;
};
jDropDown::jDropDown ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jPanel ( txt, x, y, width, height, parent, hInstance, bitmap ), capture ( false ), populated ( false )
{
RECT rect;
::GetWindowRect ( hwnd, &rect );
::MapWindowPoints ( HWND_DESKTOP, ::GetParent ( parent ), ( LPPOINT ) &rect, 2 );
items = new jItems ( "My Items List", rect.left, rect.top + height, width, 300, ::GetParent( parent ), hInstance, 0 );
items->setBackgroundColor ( RGB ( 100, 100, 100 ) );
};
jItems::jItems ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jPanel ( txt, x, y, width, height, parent, hInstance, bitmap ), wWidth ( width ), wHeight ( 30 )
{
::SetWindowPos ( this->hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
};
bool jItems::populate ( std::string myList )
{
int y = 0;
Hinstance hInstance = ::GetModuleHandle ( NULL );
std::vector < std::string > list = model::Service::explode ( "^", myList );
for ( std::vector < std::string >::const_iterator it = list.begin ( ); it != list.end ( ); ++it )
{
std::string s = *it;
jItem *i = new jItem ( "Your Item", 0, y, wWidth, wHeight, this->hwnd, hInstance, 0 );
}
::SetWindowPos ( this->hwnd, HWND_TOP, 0, 0, wWidth, list.size ( ) * wHeight, SWP_NOMOVE | SWP_NOZORDER );
return true;
};
jItem::jItem ( std::string txt, int x, int y, int width, int height, HWND parent, HINSTANCE hInstance, WORD bitmap )
: jPanel ( txt, x, y, width, height, parent, hInstance, bitmap ), empty ( false )
{
this->setBackgroundColor ( RGB ( 65, 65, 65 ) );
};
Listboxes do not auto-resize. The best we've got is:
SendMessage(my_listbox, LB_SETHORIZONTALEXTENT, 1000, 0);
MS helpfully notes that "...a list box does not update its horizontal extent dynamically."
(why the heck not...but I digress)
How can the width be set dynamically to avoid truncating the text of a message longer than 1000px?
if I understand the question... :-)
You'll essentially need to measure all of the items in the list box and calculate the maximum width of the list box contents, and then adjust the width of the listbox.
Here's some code from this project (that adds a automatic horizontal scrollbar to listboxes). This snippet is called when the font changes but it demonstrates (roughly) what's needed:
static void OnSetFont( HWND hwnd, HFONT hFont )
//
// Font has changed!
// We need to measure all of our items and reset the horizontal extent of the listbox
{
CData *pData = reinterpret_cast< CData * >( ::GetProp( hwnd, g_pcszDataProperty ) );
pData->m_hFont = hFont;
//
// Set up a HDC...
HDC hdc = GetDC( hwnd );
HGDIOBJ hOld = SelectObject( hdc, pData->m_hFont );
//
// Record the average width for use as our 'fudge factor' later.
TEXTMETRIC tm;
GetTextMetrics( hdc, &tm );
pData->m_nAvergeCharWidth = tm.tmAveCharWidth;
pData->m_nMaxWidth = 0;
//
// This is used as our item buffer. Saves us from having to handle the reallocation
// for different string lengths
CArray< TCHAR, TCHAR > arrBuffer;
//
// Quick reference to make the code below read better
CArray< int, int > &arrWidth = pData->m_arrItemWidth;
//
// The main loop. Iterate over the items, get their text from the listbox and measure
// it using our friendly little helper function.
const UINT uCount = arrWidth.GetSize();
for( UINT u = 0; u < uCount; u++ )
{
const int nLength = ::SendMessage( hwnd, LB_GETTEXTLEN, u, 0 );
arrBuffer.SetSize( nLength + 1 );
::SendMessage( hwnd, LB_GETTEXT, u, (WPARAM)arrBuffer.GetData() );
const int nItemWidth = BaseMeasureItem( pData, hwnd, hdc, arrBuffer.GetData() );
pData->m_arrItemWidth.SetAt( u, nItemWidth );
if( nItemWidth > pData->m_nMaxWidth )
{
pData->m_nMaxWidth = nItemWidth;
}
}
//
// Now, either set the horizontal extent or not, depending on whether we think we need it.
if( pData->m_nMaxWidth > pData->m_nClientWidth )
{
::SendMessage( hwnd, LB_SETHORIZONTALEXTENT, pData->m_nMaxWidth + pData->m_nAvergeCharWidth, 0 );
}
else
{
::SendMessage( hwnd, LB_SETHORIZONTALEXTENT, 0, 0 );
}
//
// The usual release of resources.
SelectObject( hdc, hOld );
ReleaseDC( hwnd, hdc );
}
and...
static int BaseMeasureItem( CData *pData, HWND hwnd, HDC hdc, LPCTSTR pcszText )
//
// Measure and item and adjust the horizontal extent accordingly.
// Because the HDC is already set up we can just do it.
// We return the width of the string so our caller can use it.
{
SIZE size;
::GetTextExtentPoint32( hdc, pcszText, _tcslen( pcszText ), &size );
if( size.cx > pData->m_nMaxWidth )
{
pData->m_nMaxWidth = size.cx;
if( pData->m_nMaxWidth > pData->m_nClientWidth )
{
::SendMessage( hwnd, LB_SETHORIZONTALEXTENT, pData->m_nMaxWidth + pData->m_nAvergeCharWidth, 0 );
}
}
return size.cx;
}
I made an editor which written in pure WinAPI. Some users want the caption icon become a drag source of the file that opened in editor, like what the explorer window does. I have no idea to implement such feature. Can someone give me example please?
Here is a sample showing how to use the system menu ("caption icon") to detect when to initiate a drag-drop operation:
class SysMenuDragSample
: public CWindowImpl< SysMenuDragSample, CWindow, CFrameWinTraits >
{
private:
static const UINT WM_SHOWSYSTEMMENU = 0x313;
bool mouse_down_in_sys_menu_;
public:
BEGIN_MSG_MAP_EX( SysMenuDragSample )
MSG_WM_NCLBUTTONDOWN( OnNcLButtonDown )
MSG_WM_NCLBUTTONUP( OnNcLButtonUp )
MSG_WM_MOUSEMOVE( OnMouseMove )
MSG_WM_LBUTTONUP( OnLButtonUp )
END_MSG_MAP()
SysMenuDragSample()
: mouse_down_in_sys_menu_( false )
{
}
void BeginDragDropOperation()
{
// TODO: Implement
}
void OnNcLButtonDown( UINT hit_test, CPoint cursor_pos )
{
if( hit_test == HTSYSMENU )
{
mouse_down_in_sys_menu_ = true;
SetCapture();
// NOTE: Future messages will come through WM_MOUSEMOVE, WM_LBUTTONUP, etc.
}
else
SetMsgHandled( FALSE );
}
void OnNcLButtonUp( UINT hit_test, CPoint cursor_pos )
{
if( hit_test == HTSYSMENU )
{
// This message and hit_test combination should never be received because
// SetCapture was called in OnNcLButtonDown.
assert( false );
}
else
SetMsgHandled( FALSE );
}
void OnMouseMove( UINT modifiers, CPoint cursor_pos )
{
if( mouse_down_in_sys_menu_ )
{
ClientToScreen( &cursor_pos );
UINT hit_test = SendMessage( WM_NCHITTEST, 0, MAKELPARAM( cursor_pos.x, cursor_pos.y ) );
if( hit_test != HTSYSMENU )
{
// The cursor has moved outside of the system menu icon so begin the drag-
// drop operation.
mouse_down_in_sys_menu_ = false;
ReleaseCapture();
BeginDragDropOperation();
}
}
else
SetMsgHandled( FALSE );
}
void OnLButtonUp( UINT modifiers, CPoint cursor_pos )
{
if( mouse_down_in_sys_menu_ )
{
// The button was released inside the system menu so simulate a normal click.
mouse_down_in_sys_menu_ = false;
ReleaseCapture();
ClientToScreen( &cursor_pos );
SendMessage( WM_SHOWSYSTEMMENU, 0, MAKELPARAM( cursor_pos.x, cursor_pos.y ) );
}
else
SetMsgHandled( FALSE );
}
};