Final toolbar item icon not showing - c++

I am wrapping the Win32 toolbar. Everything works except that whenever the user of the wrapper class adds a separator, the last toolbar item's icon does not show.
Consider this client code:
toolbarBtn tbb[] = { toolbarBtn { ID_FILE_NEW, IDI_NEW },
toolbarBtn { ID_FILE_OPEN, IDI_OPEN },
sep { },
toolbarBtn { ID_FILE_SAVEAS, IDI_SAVE },
toolbarBtn { ID_FILE_PRINT, IDI_PRINT },
sep { },
toolbarBtn { ID_EDIT_UNDO, IDI_UNDO },
toolbarBtn { ID_EDIT_REDO, IDI_REDO } };
this->tb = toolbar { *this, tbb, sizeof tbb / sizeof *tbb };
The toolbarBtn objects represent a toolbar button. The sep object is a separator, and inherits from class toolbarBtn. The following statement calls the constructor of the toolbar class, creating it. For this code, this is what I get as graphics output:
As you can see by hover, the final two buttons exist! But for a reason icon does not show, and the order is also changed of the icons. It should be "New", "Open", [Separator], "Save", "Print", [Separator], "Undo", and "Redo". But "Save As" and "Redo" do not show. And I know that the icon itself is not problem, because i can put any sequence of toolbarBtns, but as long as there is a sep object, then the last icon never displays.
Here is a implementing of relevant functions/methods:
toolbarBtn::toolbarBtn(int id, icon ico, BYTE state, BYTE style)
{
ZeroMemory(this, sizeof *this);
this->ico = ico;
this->tbb.idCommand = id;
this->tbb.fsState = state;
this->tbb.fsStyle = style;
this->tbb.iBitmap = 0; // field will be changed by toolbar c'tor
}
// count # of buttons; no separators counted
size_t nActualButtons(const toolbarBtn btns[], size_t n)
{
size_t n1 = n;
for (size_t i = 0; i < n; ++i)
if (btns[i].getTBB().fsStyle & TBSTYLE_SEP)
--n1;
return n1;
}
toolbar::toolbar(overlappedwindow parent, const toolbarBtn btns[], size_t n,
int id)
{
this->hwnd = CreateWindow(TOOLBARCLASSNAME, NULL,
WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT, 0, 0, 0, 0,
parent.gethwnd(), (HMENU) id, GetModuleHandle(NULL), NULL);
if (this->hwnd == NULL)
message(L"%s: %s", __FUNCTIONW__, geterror());
// Send the TB_BUTTONSTRUCTSIZE message, which is required for
// backward compatibility.
SendMessage(this->hwnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
HIMAGELIST imglist = ImageList_Create(16, 16, ILC_COLOR32, n, 0);
if (!imglist)
message(L"%s: %s", __FUNCTIONW__, geterror());
for (size_t i = 0; i < n; ++i) {
if (btns[i].getTBB().fsStyle & TBSTYLE_SEP)
continue; // dont add separators to image list
if (ImageList_AddIcon(imglist, btns[i].getIcon().gethandle()) == -1)
message(L"%s: %s", __FUNCTIONW__, geterror());
}
SendMessage(this->hwnd, TB_SETIMAGELIST, (WPARAM) 0, (LPARAM) imglist);
TBBUTTON *tbb = (TBBUTTON *) calloc(n, sizeof (TBBUTTON));
for (size_t i = 0; i < n; ++i) {
tbb[i] = btns[i].getTBB();
tbb[i].iBitmap = (tbb[i].fsStyle & TBSTYLE_SEP) ? 0 : i;
if (tbb[i].fsStyle & TBSTYLE_SEP)
tbb[i].idCommand = 0;
}
SendMessage(this->hwnd, TB_ADDBUTTONS, n, (LPARAM) tbb);
free(tbb);
}

I think your problem may be with this:
sep { },
Your are essentially doing this:
sep {0, 0, 0, 0}
So your separator will not have TBSTYLE_SEP set. You should probably initialize the separator like this:
sep {0, 0, 0, TBSTYLE_SEP}

Related

Set console window size on Windows

I know that there is a lot questions about how to set console size. But all found solutions are the same to my and my code doesn't works for me.
Ok, so for setting console window size, I need two functions. They are SetConsoleScreenBufferSize() and SetConsoleWindowInfo(). First version of my function:
bool SetWindowSize(size_t width, size_t height)
{
HANDLE output_handle = ::GetStdHandle(STD_OUTPUT_HANDLE);
if(output_handle == INVALID_HANDLE_VALUE)
return false;
COORD coord = {};
coord.X = static_cast<SHORT>(width);
coord.Y = static_cast<SHORT>(height);
if(::SetConsoleScreenBufferSize(output_handle, coord) == FALSE)
return false;
SMALL_RECT rect = {};
rect.Bottom = coord.X - 1;
rect.Right = coord.Y - 1;
return (::SetConsoleWindowInfo(output_handle, TRUE, &rect) != FALSE);
}
SetConsoleScreenBufferSize() will work not for all values. From documentation:
The specified width and height cannot be less than the width and
height of the console screen buffer's window
Lets try to get current window's size and call our function. To get window size, I need GetConsoleScreenBufferInfo() function. main() test code:
HANDLE output_handle = ::GetStdHandle(STD_OUTPUT_HANDLE);
if(output_handle == INVALID_HANDLE_VALUE)
return 0;
CONSOLE_SCREEN_BUFFER_INFO info = {};
if(::GetConsoleScreenBufferInfo(output_handle, &info) == FALSE)
return 0;
size_t width = info.srWindow.Right - info.srWindow.Left;
size_t height = info.srWindow.Bottom - info.srWindow.Top;
bool suc = SetWindowSize(width + 1, height + 1);
In this case SetConsoleScreenBufferSize() works fine. Next function is SetConsoleWindowInfo(). This function will work in case:
The function fails if the specified window rectangle extends beyond
the boundaries of the console screen buffer. This means that the Top
and Left members of the lpConsoleWindow rectangle (or the calculated
top and left coordinates, if bAbsolute is FALSE) cannot be less than
zero. Similarly, the Bottom and Right members (or the calculated
bottom and right coordinates) cannot be greater than (screen buffer
height – 1) and (screen buffer width – 1), respectively. The function
also fails if the Right member (or calculated right coordinate) is
less than or equal to the Left member (or calculated left coordinate)
or if the Bottom member (or calculated bottom coordinate) is less than
or equal to the Top member (or calculated top coordinate).
In our case, the values of rectangle are the same (because Left and Top are zeroes) as values of info.srWindow rectangle after call of GetConsoleScreenBufferInfo(). But! SetConsoleWindowInfo() fails with next ::GetLastError()
#err,hr ERROR_INVALID_PARAMETER : The parameter is incorrect. unsigned int
If I swap calls of this two functions:
bool SetWindowSize(size_t width, size_t height)
{
HANDLE output_handle = ::GetStdHandle(STD_OUTPUT_HANDLE);
if(output_handle == INVALID_HANDLE_VALUE)
return false;
SMALL_RECT rect = {};
rect.Bottom = static_cast<SHORT>(width);
rect.Right = static_cast<SHORT>(height);
if(::SetConsoleWindowInfo(output_handle, TRUE, &rect) == FALSE)
return false;
COORD coord = {};
coord.X = rect.Bottom + 1;
coord.Y = rect.Right + 1;
return (::SetConsoleScreenBufferSize(output_handle, coord) != FALSE);
}
then I will have the same error.
So, how can I use SetConsoleScreenBufferSize() and SetConsoleWindowInfo() correctly ?
SetConsoleWindowInfo() does not reposition the console window on the screen. The name of this function is misleading. It rather scrolls the current visible portion inside the console window. See this sample here.
If you want to set the position of a console window that runs your programm, use code such as:
HWND hwnd = GetConsoleWindow();
RECT rect = {100, 100, 300, 500};
MoveWindow(hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,TRUE);
From the TurboVision port:
void TDisplay::setCrtMode( ushort mode )
{
int oldr = getRows();
int oldc = getCols();
int cols = uchar(mode >> 8);
int rows = uchar(mode);
if ( cols == 0 ) cols = oldc;
if ( rows == 0 ) rows = oldr;
checksize(rows, cols);
COORD newSize = { cols, rows };
SMALL_RECT rect = { 0, 0, cols-1, rows-1 };
if ( oldr <= rows )
{
if ( oldc <= cols )
{ // increasing both dimensions
BUFWIN:
SetConsoleScreenBufferSize( TThreads::chandle[cnOutput], newSize );
SetConsoleWindowInfo( TThreads::chandle[cnOutput], True, &rect );
}
else
{ // cols--, rows+
SMALL_RECT tmp = { 0, 0, cols-1, oldr-1 };
SetConsoleWindowInfo( TThreads::chandle[cnOutput], True, &tmp );
goto BUFWIN;
}
}
else
{
if ( oldc <= cols )
{ // cols+, rows--
SMALL_RECT tmp = { 0, 0, oldc-1, rows-1 };
SetConsoleWindowInfo( TThreads::chandle[cnOutput], True, &tmp );
goto BUFWIN;
}
else
{ // cols--, rows--
SetConsoleWindowInfo( TThreads::chandle[cnOutput], True, &rect );
SetConsoleScreenBufferSize( TThreads::chandle[cnOutput], newSize );
}
}
GetConsoleScreenBufferInfo( TThreads::chandle[cnOutput], &TThreads::sbInfo );
}
ushort TDisplay::getRows()
{
GetConsoleScreenBufferInfo( TThreads::chandle[cnOutput], &TThreads::sbInfo );
return TThreads::sbInfo.dwSize.Y;
}
ushort TDisplay::getCols()
{
GetConsoleScreenBufferInfo( TThreads::chandle[cnOutput], &TThreads::sbInfo );
return TThreads::sbInfo.dwSize.X;
}
I solved this issue by making these functions which can get/set the console window/buffer sizes in characters taking into account increasing the buffer size if needed, console font size, window borders and all that jazz.
The variables at play here to understand:
Windows have a client area, which is the coordinates (in pixels) excluding the borders
Windows have a window area, which is the coordinates (in pixels) including the borders
Console has a view area, which is the window size in characters
Console has a screen buffer, which is the scrollable buffer size in characters
Console has a font size, which is the character size in coordinates (pixels)
Console's screen buffer cannot be smaller than the view area
You need to correctly mix and match these around to achieve the desired result.
These functions are plug-n-play so you don't need to worry about none of that though.
All functions return TRUE (1) on success and FALSE (0) on error.
Set Console Window Size
static BOOL SetConsoleSize(int cols, int rows) {
HWND hWnd;
HANDLE hConOut;
CONSOLE_FONT_INFO fi;
CONSOLE_SCREEN_BUFFER_INFO bi;
int w, h, bw, bh;
RECT rect = {0, 0, 0, 0};
COORD coord = {0, 0};
hWnd = GetConsoleWindow();
if (hWnd) {
hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConOut && hConOut != (HANDLE)-1) {
if (GetCurrentConsoleFont(hConOut, FALSE, &fi)) {
if (GetClientRect(hWnd, &rect)) {
w = rect.right-rect.left;
h = rect.bottom-rect.top;
if (GetWindowRect(hWnd, &rect)) {
bw = rect.right-rect.left-w;
bh = rect.bottom-rect.top-h;
if (GetConsoleScreenBufferInfo(hConOut, &bi)) {
coord.X = bi.dwSize.X;
coord.Y = bi.dwSize.Y;
if (coord.X < cols || coord.Y < rows) {
if (coord.X < cols) {
coord.X = cols;
}
if (coord.Y < rows) {
coord.Y = rows;
}
if (!SetConsoleScreenBufferSize(hConOut, coord)) {
return FALSE;
}
}
return SetWindowPos(hWnd, NULL, rect.left, rect.top, cols*fi.dwFontSize.X+bw, rows*fi.dwFontSize.Y+bh, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
}
}
}
}
}
}
return FALSE;
}
/* usage */
SetConsoleSize(80, 40);
Get Console Window Size
static BOOL GetConsoleSize(int* cols, int* rows) {
HWND hWnd;
HANDLE hConOut;
CONSOLE_FONT_INFO fi;
int w, h;
RECT rect = {0, 0, 0, 0};
hWnd = GetConsoleWindow();
if (hWnd) {
hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConOut && hConOut != (HANDLE)-1) {
if (GetCurrentConsoleFont(hConOut, FALSE, &fi)) {
if (GetClientRect(hWnd, &rect)) {
w = rect.right-rect.left;
h = rect.bottom-rect.top;
*cols = w / fi.dwFontSize.X;
*rows = h / fi.dwFontSize.Y;
return TRUE;
}
}
}
}
return FALSE;
}
/* usage */
int cols, rows;
GetConsoleSize(&cols, &rows);
Set Console Buffer Size
static BOOL SetConsoleBufferSize(int cols, int rows) {
HANDLE hConOut;
CONSOLE_SCREEN_BUFFER_INFO bi;
COORD coord = {0, 0};
hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConOut && hConOut != (HANDLE)-1) {
if (GetConsoleScreenBufferInfo(hConOut, &bi)) {
coord.X = cols;
coord.Y = rows;
return SetConsoleScreenBufferSize(hConOut, coord);
}
}
return FALSE;
}
/* usage */
SetConsoleBufferSize(80, 300);
Get Console Buffer Size
static BOOL GetConsoleBufferSize(int* cols, int* rows) {
HANDLE hConOut;
CONSOLE_SCREEN_BUFFER_INFO bi;
hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConOut && hConOut != (HANDLE)-1) {
if (GetConsoleScreenBufferInfo(hConOut, &bi)) {
*cols = bi.dwSize.X;
*rows = bi.dwSize.Y;
return TRUE;
}
}
return FALSE;
}
/* usage */
int cols, rows;
GetConsoleBufferSize(&cols, &rows);

How do I prevent flickering on CTreeCtrl?

I am using VS2010 to develop a MFC project. When I clicked on an item of a CTreeCtrl control, It's so strange that some other unrelated items flickers sometimes. I tried many computers, and this problem still exists. Any solutions?
This is a BCGControlBar project, the CTreeCtrl is linked with a CWorkSpaceBar2 class (Like the workspace bar in VS). I think this is not the point, because many other pure CTreeList demos also share the same flicker problem. A demo is provided below, you can find the flicker problem when you click an CTreeCtrl item. Although it is not my code, but we share the same problem.
http://www.verysource.com/testmytreectrl-59412.html
Below is some pieces of my code. You can find that I didn't do something strange that maybe cause the problem.
initIcons() function is for initializing icons for the items.
add2Tree(CTreeCtrl* pTree, AFDir* pDir, HTREEITEM hItemParent, bool bHead) function is for adding items.
OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) function does nothing when an item is clicked.
void CWorkSpaceBar2::initIcons()
{
// SHFILEINFO sfi;
// SHGetFileInfo(m_strDataDir, 0, &sfi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
// m_iIconFolder = sfi.iIcon;
//
// SHFILEINFO sfi2;
// SHGetFileInfo(m_strDataDir + _T("coloring_rules.txt"), 0, &sfi2, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
// m_iIconScript = sfi2.iIcon;
//
// SHFILEINFO sfi3;
// SHGetFileInfo(m_strDataDir + _T("color2.ini"), 0, &sfi3, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
// m_iIconProperty = sfi3.iIcon;
// HICON hIcon;
// hIcon = AfxGetApp()->LoadIcon(IDB);
/* Cil1.Create(IDB_VSICON, 16, 1, RGB(255, 0, 255)); // 建立16 位图像控制*/
m_imageList.Create(16, 16, ILC_COLOR32 | ILC_MASK, 10, 10);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_VSICON);
m_imageList.Add(&bitmap, RGB(255, 0, 255));
// int bbb = Cil1.Add(aaa.FromHandle((HBITMAP) aaa), RGB(0, 0, 0));
//Cil1.Add(LoadIcon(NULL, (LPCTSTR) IDR_AffensicsTYPE));// 增加选中状态图像
m_wndTree.SetImageList(&m_imageList, TVSIL_NORMAL); //LVSIL_SMALL
m_iIconFolderClosed = LIST_ICON_FOLDER_CLOSED;
m_iIconScript = LIST_ICON_SCRIPT;
m_iIconProperty = LIST_ICON_PROPERTY;
//
// HTREEITEM root = m_wndTree.InsertItem(_T("root"), 0, 0);
// int i,j;
// for (i = 0; i < 4; i++)
// {
// HTREEITEM item = m_wndTree.InsertItem(_T("item"), 1, 1,root);
// for (j = 0; j < 3; j++)
// {
// m_wndTree.InsertItem(_T("small"), 0, 1, item);
// }
// }
}
void CWorkSpaceBar2::add2Tree(CTreeCtrl* pTree, AFDir* pDir, HTREEITEM hItemParent, bool bHead)
{
HTREEITEM hItem;
int iIcon = pDir->is_dir? m_iIconFolderClosed : m_iIconScript;
if (bHead)
{
hItem = pTree->InsertItem(pDir->name, iIcon, iIcon, TVI_ROOT);
m_mapDirs[hItem] = pDir;
m_mapDirs_R[pDir] = hItem;
}
else
{
hItem = pTree->InsertItem(pDir->name, iIcon, iIcon, hItemParent);
m_mapDirs[hItem] = pDir;
m_mapDirs_R[pDir] = hItem;
}
if (pDir->is_dir == TRUE)
{
for (size_t i = 0; i < pDir->dirs.size(); i ++)
{
add2Tree(pTree, pDir->dirs[i], hItem, FALSE);
}
for (size_t i = 0; i < pDir->files.size(); i ++)
{
add2Tree(pTree, pDir->files[i], hItem, FALSE);
}
}
else
{
addScript2Tree(pTree, pDir, hItem);
}
}
void CWorkSpaceBar2::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
return;
}

c++ Virtual ListView in Tile view, can't get subitems to appear

I have a straight win32 c++ app and I'm filling the window with a ListView whose view type is set to LV_VIEW_TILE and I'm also setting the style to LVS_OWNERDATA.
I'm having trouble trying to work out how to get the subitems to show. This code creates the view.
DWORD exstyle =WS_EX_CLIENTEDGE|LVS_EX_DOUBLEBUFFER|LVS_EX_JUSTIFYCOLUMNS|LVS_EX_INFOTIP;
g_hwndList = CreateWindowEx(exstyle, WC_LISTVIEW, NULL, WS_CHILD | WS_VISIBLE | LVS_ICON | LVS_OWNERDATA, 0, 0, 0, 0, hWnd, (HMENU) 2702, hInst, NULL);
ListView_SetView(g_hwndList, LV_VIEW_TILE);
LVTILEVIEWINFO tileViewInfo = { };
tileViewInfo.cbSize = sizeof(LVTILEVIEWINFO);
tileViewInfo.dwFlags = LVTVIF_AUTOSIZE;
tileViewInfo.dwMask = LVTVIM_COLUMNS;
tileViewInfo.cLines = 1;
BOOL tst = ListView_SetTileViewInfo(g_hwndList, &tileViewInfo);
I only want one more subitem/column to appear. In my LVN_GETDISPINFO I currently have this:
static int colfmt[1];
colfmt[0] = LVCFMT_LEFT;
static int order[1];
order[0] = 1;
if ((nimfo->item.mask & LVIF_COLUMNS) == LVIF_COLUMNS) {
nimfo->item.cColumns = 1;
nimfo->item.piColFmt = PINT(colfmt);
nimfo->item.puColumns = PUINT(order);
}
if ((nimfo->item.mask & LVIF_TEXT) == LVIF_TEXT) {
nimfo->item.pszText = di->LABEL;
}
if ((nimfo->item.mask & LVIF_IMAGE) == LVIF_IMAGE) {
nimfo->item.iImage = di->IMAGE_INDEX;
}
I can't work out at what point and where I need to supply the subitem/column text, I'm never seeing the nimfo->item.subitem changing from 0 and for each call for LVIF_TEXT the structure values are always the same.
So at what point do I need to supply the extra textual data?
Many thanks.
I, rather stupidly, wasn't adding any columns and therefore wasn't being asked for the other items.
added this and everything works
LVCOLUMN col = {};
col.mask = LVCF_SUBITEM;
col.iSubItem = 0;
ListView_InsertColumn(g_hwndList, 0, &col);

Get text in a listbox control added to a child window

I want to add the text in a listbox control to the child of my main window. The child is essentially an edit control, but is not a dialog. I have tried a few different functions already with no success, I believe my problem is that I need to somehow switch focus from the dialog window to the child window before adding the text. I would prefer not to get an answer with specific code, but if I could be pointed to a helpful function or concept, that would be great!
EDIT: The listbox is part of a larger dialog window that allows the user to enter text and then add it to the list. These functions are working very well. What I'd like to do is get the text that is added to the list moved into the child window when the user clicks a button on the dialog, preferably without the user having to select the items before clicking the button.
There's a lot of code, but I think these pieces are relevant:
Child window:
case WM_CREATE:
{
hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
0, 0, 100, 100, w, (HMENU) IDC_EDIT, NULL, NULL);
if (hEdit == NULL){
MessageBox(NULL, "Could not create child window :(", "ERROR", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
}
break;
case WM_SIZE:
{
RECT wSize;
GetClientRect(w, &wSize);
SetWindowPos(hEdit, NULL, 0, 0, wSize.right, wSize.bottom, NULL);
}
Function to add text to child window by clicking a button on the dialog (HWND hEdit, the child window, is defined globally):
case ID_ADDMAIN:
{
HWND hList = GetDlgItem(w, IDC_LIST1);
int count = SendMessage(hList, LB_GETCOUNT, NULL, NULL);
if (count > 0){
DWORD textLength = GetWindowTextLength(hList);
LPSTR alloc;
alloc = (LPSTR) GlobalAlloc(GPTR, textLength + 1);
if(GetWindowText(hList, alloc, textLength + 1)){
SendMessage(hEdit, WM_SETTEXT, NULL, (LPARAM) alloc);
}
GlobalFree(alloc);
}
else{
MessageBox(NULL, "There's nothing to add!", "???", MB_ICONINFORMATION | MB_OK);
}
}
break;
Besides the SendMessage function, I also tried SetWindowText and I tried getting each string in the listbox separately using a for loop rather than GetWindowText. Thank you in advance for your help.
You misunderstand the list box. The LB_GETCOUNT message is used to get the number of items (rows) in the list box. (Not the number of characters.)
GetWindowText is not appropriate for a list box: It gets the titlebar text, but a list box has no titlebar. What you can do with a list box is find out which row is selected (LB_GETCURSEL) and then get the text from that row (LB_GETTEXT).
Here is a list of functions I wrote for my WINAPI class library..
int ListBox::GetItemCount() const
{
return SendMessage(Control::GetHandle(), LB_GETCOUNT, 0, 0);
}
int ListBox::GetSelectedIndex() const
{
return SendMessage(Control::GetHandle(), LB_GETCURSEL, 0, 0);
}
void ListBox::SetSelectedIndex(int Index)
{
SendMessage(Control::GetHandle(), LB_SETCURSEL, Index, 0);
}
void ListBox::AddItem(const tstring &Item, int Index)
{
SendMessage(Control::GetHandle(), Index == 0 ? LB_ADDSTRING : LB_INSERTSTRING, Index, reinterpret_cast<LPARAM>(Item.c_str()));
}
void ListBox::RemoveItem(int Index)
{
SendMessage(Control::GetHandle(), LB_DELETESTRING, Index, 0);
}
void ListBox::Clear()
{
SendMessage(Control::GetHandle(), LB_RESETCONTENT, 0, 0);
}
int ListBox::GetIndexOf(const tstring &Item)
{
return SendMessage(Control::GetHandle(), LB_FINDSTRINGEXACT, -1, reinterpret_cast<LPARAM>(Item.c_str()));
}
int ListBox::GetIndexPartial(const tstring &Item)
{
return SendMessage(Control::GetHandle(), LB_FINDSTRING, -1, reinterpret_cast<LPARAM>(Item.c_str()));
}
void ListBox::SetColumnWidth(int Width)
{
SendMessage(Control::GetHandle(), LB_SETCOLUMNWIDTH, Width, 0);
}
tstring ListBox::GetItem(int Index) const
{
std::vector<char> Buffer(SendMessage(Control::GetHandle(), LB_GETTEXTLEN, Index, 0) + 1);
SendMessage(Control::GetHandle(), LB_GETTEXT, Index, reinterpret_cast<LPARAM>(Buffer.data()));
return tstring(Buffer.begin(), Buffer.end());
}
You'll need:
ListBox::GetItem(ListBox::GetSelectedIndex());
to get the text of the current item in the list box..
For the Edit control, I have:
void TextBox::SetReadOnly(bool ReadOnly)
{
SendMessage(Control::GetHandle(), EM_SETREADONLY, ReadOnly, 0);
}
void TextBox::SetPassword(bool Enabled, char PasswordChar)
{
SendMessage(Control::GetHandle(), EM_SETPASSWORDCHAR, Enabled ? PasswordChar : 0, 0);
}
std::uint32_t TextBox::GetTextLength() const
{
return GetWindowTextLength(Control::GetHandle());
}
void TextBox::ShowScrollBar(bool Show, int wBar)
{
::ShowScrollBar(Control::GetHandle(), wBar, true);
}
void TextBox::AppendText(const tstring &Text) const
{
SendMessage(Control::GetHandle(), EM_SETSEL, -1, -1);
SendMessage(Control::GetHandle(), EM_REPLACESEL, 0, reinterpret_cast<LPARAM>(Text.c_str()));
}
tstring TextBox::GetText() const
{
std::vector<TCHAR> Buffer(GetWindowTextLength(Control::GetHandle()) + 1);
GetWindowText(Control::GetHandle(), Buffer.data(), Buffer.size());
return tstring(Buffer.begin(), Buffer.end());
}
void TextBox::SetText(const tstring &Text)
{
this->Title = Text;
SetWindowText(Handle, Text.c_str());
}
You can get the text from the edit box easily with these.. I hope these aid you greatly..

SDL / C++: How to make this function short(er)?

I have this:
void showNumbers(){
nrBtn1 = TTF_RenderText_Blended( fontnrs, "1", sdlcolors[0] );
nrBtn2 = TTF_RenderText_Blended( fontnrs, "2", sdlcolors[1] );
nrBtn3 = TTF_RenderText_Blended( fontnrs, "3", sdlcolors[2] );
nrBtn4 = TTF_RenderText_Blended( fontnrs, "4", sdlcolors[3] );
nrBtn5 = TTF_RenderText_Blended( fontnrs, "5", sdlcolors[4] );
nrBtn6 = TTF_RenderText_Blended( fontnrs, "6", sdlcolors[5] );
nrBtn7 = TTF_RenderText_Blended( fontnrs, "7", sdlcolors[6] );
nrBtn8 = TTF_RenderText_Blended( fontnrs, "8", sdlcolors[7] );
nrBtn9 = TTF_RenderText_Blended( fontnrs, "9", sdlcolors[8] );
SDL_Rect rcnrBtn1 = { 40, 32, 0, 0 };
SDL_Rect rcnrBtn2 = { 70, 32, 0, 0 };
SDL_Rect rcnrBtn3 = { 100, 32, 0, 0 };
SDL_Rect rcnrBtn4 = { 130, 32, 0, 0 };
SDL_Rect rcnrBtn5 = { 160, 32, 0, 0 };
SDL_Rect rcnrBtn6 = { 190, 32, 0, 0 };
SDL_Rect rcnrBtn7 = { 220, 32, 0, 0 };
SDL_Rect rcnrBtn8 = { 250, 32, 0, 0 };
SDL_Rect rcnrBtn9 = { 280, 32, 0, 0 };
SDL_BlitSurface(nrBtn1, NULL, screen, &rcnrBtn1); SDL_FreeSurface(nrBtn1);
SDL_BlitSurface(nrBtn2, NULL, screen, &rcnrBtn2); SDL_FreeSurface(nrBtn2);
SDL_BlitSurface(nrBtn3, NULL, screen, &rcnrBtn3); SDL_FreeSurface(nrBtn3);
SDL_BlitSurface(nrBtn4, NULL, screen, &rcnrBtn4); SDL_FreeSurface(nrBtn4);
SDL_BlitSurface(nrBtn5, NULL, screen, &rcnrBtn5); SDL_FreeSurface(nrBtn5);
SDL_BlitSurface(nrBtn6, NULL, screen, &rcnrBtn6); SDL_FreeSurface(nrBtn6);
SDL_BlitSurface(nrBtn7, NULL, screen, &rcnrBtn7); SDL_FreeSurface(nrBtn7);
SDL_BlitSurface(nrBtn8, NULL, screen, &rcnrBtn8); SDL_FreeSurface(nrBtn8);
SDL_BlitSurface(nrBtn9, NULL, screen, &rcnrBtn9); SDL_FreeSurface(nrBtn9);
}
But for 60 buttons. Is there a way how to do something like:
void showNumbers()
{
SDL_Rect rcnrBtn1 = { 40, 32, 0, 0 };
SDL_Rect rcnrBtn2 = { 70, 32, 0, 0 };
SDL_Rect rcnrBtn3 = { 100, 32, 0, 0 };
SDL_Rect rcnrBtn4 = { 130, 32, 0, 0 };
SDL_Rect rcnrBtn5 = { 160, 32, 0, 0 };
SDL_Rect rcnrBtn6 = { 190, 32, 0, 0 };
SDL_Rect rcnrBtn7 = { 220, 32, 0, 0 };
SDL_Rect rcnrBtn8 = { 250, 32, 0, 0 };
SDL_Rect rcnrBtn9 = { 280, 32, 0, 0 };
for(int x=1; x<=60;x++){
nrBtn+x = TTF_RenderText_Blended( fontnrs, x, sdlcolors[x-1] );
SDL_BlitSurface(nrBtn+x, NULL, screen, &rcnrBtn+x); SDL_FreeSurface(nrBtn+x);
}
}
You need to use an array.
E.g.
SDL_Rect rcnrBtn[60];
for(int x = 0; x < 60; x++) {
rcnrBtn[x].x = 30 * x + 10;
rcnrBtn[x].y = 32;
rcnrBtn[x].w = 100;
rcnrBtn[x].h = 24;
}
Arrays always start at 0, and this particular one ends at 59 giving a total of 60 elements.
You could do something like this :
void showNumbers() {
SDL_Surface* nrBtn = NULL;
int nbr = 1;
int x = 30; // your starting x
int i = 0;
for (; i < 60; ++i) {
nrBtn = TTF_RenderText_Blended(fontnrs, nbr_to_str(nbr), sdlcolors[i]); // You'll have to code nbr_to_str
SDL_Rect rect = {x, 32, 0, 0}; // Are you sure that width and height are 0 ?
SDL_BlitSurface(nrBtn, NULL, screen, &rect);
SDL_FreeSurface(nrBtn);
x += 30;
}
return;
}
It appears your entire function could be replaced with the following array-based variation. Assuming that your nrBtnXX variables are defined outside the function and you want to minimise the scope of changes, you should look at something like:
#define BUTTON_COUNT 60
SDL_Surface *nrBtn[BUTTON_COUNT];
void showNumbers () {
char textNum[3];
for (int i = 0; i < BUTTON_COUNT; i++) {
sprintf (textNum, "%d", i);
nrBtn[i] = TTF_RenderText_Blended( fontnrs, textNum, sdlcolors[i] );
}
SDL_Rect rcnrBtn[BUTTON_COUNT];
for (int i = 0; i < BUTTON_COUNT; i++) {
rcnrBtn[i].x = 40 + i * 30; // use formulae for all these.
rcnrBtn[i].y = 32;
rcnrBtn[i].w = 0;
rcnrBtn[i].h = 0;
}
for (int i = 0; i < BUTTON_COUNT; i++) {
SDL_BlitSurface(nrBtn[i], NULL, screen, &rcnrBtn[i]);
SDL_FreeSurface(nrBtn[i]);
}
}
The idea is to store everything in arrays so that you don't have to deal with individual variables. If the nrBtn variables are required to be a non-array, then I would set up a single array of pointers to them so this approach would still work, something like:
SDL_Surface *nrBtnPtr[] = { &nrBtn1, &nrBtn2 ..., &nrBtn60 };
You should also set the formulae intelligently for the x and y coordinates since you probably don't want a 60x1 matrix for them. Look into making it 12x5 or something equally as compact.