Repositioning of MFCToolBars - c++

I am using Visual Studio 2019, I created an MDI application.
I have placed 4 toolbars in a row in CMainFrame (derived from CMDIFrameWndEx).
Depending on the active view I hide one toolbar, and thus it’s possible have a gap
between two toolbars.
How can I close the gap automatically by attaching the right toolbar to the left?
Here is my code:
LRESULT CMainFrame::OnActivateViewSelect(WPARAM w, LPARAM l)
{
if (m_bViewInit)
{
auto iViewSelect = _S32(w);
if (iViewSelect != m_lastpane)
{
m_lastpane = iViewSelect;
ShowPane(&m_wndToolBar[0], iViewSelect == 0, FALSE, iViewSelect == 0);
ShowPane(&m_wndToolBar[1], iViewSelect == 1, FALSE, iViewSelect == 1);
ShowPane(&m_wndToolBar[2], iViewSelect == 2, FALSE, iViewSelect == 2);
ShowPane(&m_wndToolBar[3], iViewSelect == 3, FALSE, iViewSelect == 3);
RecalcLayout();
}
}
return 0L;
}

Related

C++ how can I simplify this if else statement?

I would like to know how I could simplify a statement like the one below.
I have similar code everywhere, and would like to clear it up.
if(isActive)
{
if(columnId == 4)
g.drawText(active[row].value, 2, 0, width, height, Justification::centredLeft, true);
}
else
{
if(columnId == 4)
g.drawText(inactive[row].value, 2, 0, width, height, Justification::centredLeft, true);
}
isActive, as you can imagine, is a bool value.
At first glance, it's most apparent that this code only does anything if columnId == 4.
if(columnId == 4)
{
if(isActive)
{
g.drawText(active[row].value, 2, 0, width, height, Justification::centredLeft, true);
}
else
{
g.drawText(inactive[row].value, 2, 0, width, height, Justification::centredLeft, true);
}
}
At second glance, those two bulky lines are almost the same.
if(columnId == 4)
{
auto & text = isActive ? active : inactive;
g.drawText(text[row].value, 2, 0, width, height, Justification::centredLeft, true);
}
Note, also, the valid comment from #eerorika. ⬇️ I couldn't say it better than they did.
if (columnId != 4)
; // do nothing
else if (isActive)
. . .
else
. . .
A lambda could be used to simplify the original code structure, by reducing the amount of duplicated text.
auto drawText = [&](auto &table) {
g.drawText(table[row].value, 2, 0, width, height,
Justification::centeredLeft, true);
};
if(isActive)
{
if(columnId == 4) drawText(active);
}
else
{
if(columnId == 4) drawText(inactive);
}

Final toolbar item icon not showing

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}

moving window and resize bottom flickers

I am trying to make a kind of popup notification window that slides out of the task bar.
At the moment I am only trying to get it to work if the taskbar is on bottom of screen, I have it working like it should.
But the problem im having is when the window is starting to appear/slide the bottom part of it flickers (depending on how big i have set my m_nIncrement value, it flashes the bottom area the same size as the m_nIncrement value)
The window disappears fine with no flicker.
//MyWindow
WNDCLASS wc =
{
CS_HREDRAW | CS_VREDRAW, __sWndProcDlg, 0, 0, g_hInst, nullptr,
LoadCursor(nullptr, IDC_ARROW), (HBRUSH)::GetStockObject(BLACK_BRUSH),
nullptr, m_lpszClassName
};
if (!RegisterClass(&wc))
return;
m_hWnd = CreateWindowEx(WS_EX_NOACTIVATE, m_lpszClassName, NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, m_hWndParent, NULL, g_hInst, NULL);
//ShowWindow
void _ShowWindow(int _show)
{
unsigned int nDesktopWidth = m_rcDesktop.right - m_rcDesktop.left;
unsigned int nDesktopHeight = m_rcDesktop.bottom - m_rcDesktop.top;
unsigned int nScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
unsigned int nScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
BOOL bTaskbarOnRight = nDesktopWidth<nScreenWidth && m_rcDesktop.left == 0;
BOOL bTaskbarOnLeft = nDesktopWidth<nScreenWidth && m_rcDesktop.left != 0;
BOOL bTaskBarOnTop = nDesktopHeight<nScreenHeight && m_rcDesktop.top != 0;
BOOL bTaskbarOnBottom = nDesktopHeight<nScreenHeight && m_rcDesktop.top == 0;
if (_show)
{
ShowWindow(m_hWnd, SW_SHOW);
if (bTaskbarOnBottom)
{
m_nCurrentPos.cx = m_rcDesktop.right - m_sMaxSize.cx;
m_nCurrentPos.cy = m_rcDesktop.bottom - m_nCurrentSize.cy;
m_nTaskbarPlacement = TASKBAR_ON_BOTTOM;
}
KillTimer(m_hWnd, IDT_DISAPPEARING);
SetTimer(m_hWnd, IDT_APPEARING, 1, nullptr);
}
else
{
KillTimer(m_hWnd, IDT_APPEARING);
if (bTaskbarOnRight)
m_nCurrentPos.cx = m_rcDesktop.right - m_sMaxSize.cx;
else if (bTaskbarOnLeft)
m_nCurrentPos.cx = m_rcDesktop.left;
else if (bTaskBarOnTop)
m_nCurrentPos.cy = m_rcDesktop.top;
else //if (bTaskbarOnBottom)
m_nCurrentPos.cy = m_rcDesktop.bottom - m_nCurrentSize.cy;
SetTimer(m_hWnd, IDT_DISAPPEARING, 1, NULL);
}
}
//__OnTimer
LRESULT __OnTimer(HWND hWnd, UINT nIDEvent)
{
int m_nIncrement = 20;
if (nIDEvent == IDT_APPEARING)
{
switch (m_nTaskbarPlacement)
{
case TASKBAR_ON_BOTTOM:
if (m_nCurrentPos.cy > (m_rcDesktop.bottom - m_sMaxSize.cy))
{
m_nCurrentPos.cy -= m_nIncrement;
m_nCurrentSize.cy = m_rcDesktop.bottom - m_nCurrentPos.cy;
}
else
KillTimer(hWnd, IDT_APPEARING);
break;
}
SetFocus(hWnd);
SetWindowPos(hWnd, HWND_TOPMOST, m_nCurrentPos.cx, m_nCurrentPos.cy, m_sMaxSize.cx, m_nCurrentSize.cy, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE);
}
else if (nIDEvent == IDT_DISAPPEARING)
{
switch (m_nTaskbarPlacement)
{
case TASKBAR_ON_BOTTOM:
if (m_nCurrentPos.cy < m_rcDesktop.bottom)
{
m_nCurrentPos.cy += m_nIncrement;
m_nCurrentSize.cy = m_rcDesktop.bottom - m_nCurrentPos.cy;
}
else
{
KillTimer(hWnd, IDT_DISAPPEARING);
MoveWindow(m_hWnd, 0, 0, 0, 0, FALSE);
ShowWindow(m_hWnd, SW_HIDE);
}
break;
}
SetWindowPos(hWnd, HWND_TOPMOST, m_nCurrentPos.cx, m_nCurrentPos.cy, m_sMaxSize.cx, m_nCurrentSize.cy, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE);
}
return true;
}
use AnimateWindow instead. it is easy to use. you may need to handle WM_PRINT, and this also is quit straightforward.
if ever you want to keep working on your code then:
1) remove from popup class the flags CS_HREDRAW & CS_VREDRAW
2) handle WM_ERASEBACKGROUND
finally. if it is a popup window, do not call SetFocus(); maybe you have to set zorder to TOP_MOST
good luck

Does CMFCStatusBar::SetPaneIcon supports alpha icon?

My App setup icons for panes in status bar (class CMFCStatusBar). There is only one method for this task - CMFCStatusBar::SetPaneIcon(). But if icon have alpha channel this method loads wrong image (on black background).
I looked into the source code and I saw that CMFCStatusBar uses internal HIMAGELISTs for every panes. All this HIMAGELIST creates with flag ILC_MASK | ILC_COLORDDB, not ILC_COLOR32 or ILC_COLOR24.
This is a bug!
So, is there a way to use the icons with alpha channel in CMFCStatusBar panes?
Example:
HICON hIcon = ::LoadImage(hModule, MAKEINTRESOURCE(nIconID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
m_StatusBar.SetPaneIcon(m_StatusBar.CommandToIndex(ID_INDICATOR_1), hIcon);
Microsoft developed the CMFC classes (Feature Pack) from the BCG toolkit. If you compare the CMFCStatusBar::SetPaneIcon() method with the BCG method from the same class, you’ll notice a few subtle differences.
BCG defines its method with a flag for alpha blend. The method looks like:
void CBCGPStatusBar::SetPaneIcon (int nIndex, HBITMAP hBmp,
COLORREF clrTransparent, BOOL bUpdate, BOOL bAlphaBlend/* = FALSE*/)
The CMFC equivalent removes the ‘bAlphaBlend’ flag.
Comparing the method code, you’ll see that BCG uses the following code that has been removed from the CMFC version:
DWORD dwFlags = ILC_MASK | ILC_COLORDDB;
if (bAlphaBlend)
{
dwFlags = ILC_COLOR32;
}
pSBP->hImage = ::ImageList_Create (pSBP->cxIcon, pSBP->cyIcon, dwFlags, 1, 0);
I’m not sure why the CMFC version differs so much (Microsoft may have a valid reason), but, I’ve included the BCG version below. I would study the BCG version and possibly create your own ‘SetPaneIcon’ method from that code (at your own risk).
void CBCGPStatusBar::SetPaneIcon (int nIndex, HBITMAP hBmp,
COLORREF clrTransparent, BOOL bUpdate, BOOL bAlphaBlend/* = FALSE*/)
{
ASSERT_VALID(this);
CBCGStatusBarPaneInfo* pSBP = _GetPanePtr(nIndex);
if (pSBP == NULL)
{
ASSERT (FALSE);
return;
}
// Disable animation (if exist):
SetPaneAnimation (nIndex, NULL, 0, FALSE);
if (hBmp == NULL)
{
if (pSBP->hImage != NULL)
{
::ImageList_Destroy (pSBP->hImage);
}
pSBP->hImage = NULL;
if (bUpdate)
{
InvalidatePaneContent (nIndex);
}
return;
}
BITMAP bitmap;
::GetObject (hBmp, sizeof (BITMAP), &bitmap);
if (pSBP->hImage == NULL)
{
pSBP->cxIcon = bitmap.bmWidth;
pSBP->cyIcon = bitmap.bmHeight;
DWORD dwFlags = ILC_MASK | ILC_COLORDDB;
if (bAlphaBlend)
{
dwFlags = ILC_COLOR32;
}
pSBP->hImage = ::ImageList_Create (pSBP->cxIcon, pSBP->cyIcon, dwFlags, 1, 0);
RecalcLayout ();
}
else
{
ASSERT (pSBP->cxIcon == bitmap.bmWidth);
ASSERT (pSBP->cyIcon == bitmap.bmHeight);
::ImageList_Remove (pSBP->hImage, 0);
}
//---------------------------------------------------------
// Because ImageList_AddMasked changes the original bitmap,
// we need to create a copy:
//---------------------------------------------------------
HBITMAP hbmpCopy = (HBITMAP) ::CopyImage (hBmp, IMAGE_BITMAP, 0, 0, 0);
if (bAlphaBlend)
{
::ImageList_Add (pSBP->hImage, hbmpCopy, NULL);
}
else
{
::ImageList_AddMasked (pSBP->hImage, hbmpCopy, clrTransparent);
}
::DeleteObject (hbmpCopy);
if (bUpdate)
{
InvalidatePaneContent (nIndex);
}
}
My solution, based in rrirower code.
CMFCStatusBarPaneInfo* CMyStatusBar::GetPane(int nIndex) const {
if (nIndex == 255 && m_nCount < 255) {
// Special case for the simple pane
for (int i = 0; i < m_nCount; i++)
{
CMFCStatusBarPaneInfo* pSBP = GetPane(i);
ENSURE(pSBP != NULL);
if (pSBP->nStyle & SBPS_STRETCH) {
return pSBP;
}
}
}
if (nIndex < 0 || nIndex >= m_nCount) {
return NULL;
}
if (m_pData == NULL) {
ASSERT(FALSE);
return NULL;
}
return((CMFCStatusBarPaneInfo*)m_pData) + nIndex;
}
void CMyStatusBar::SetPaneIcon(int nIndex, HICON hIcon, BOOL bUpdate /*= TRUE*/)
{
ASSERT_VALID(this);
CMFCStatusBarPaneInfo* pSBP = GetPane(nIndex);
if (pSBP == NULL)
{
ASSERT(FALSE);
return;
}
// Disable animation(if exist):
SetPaneAnimation(nIndex, NULL, 0, FALSE);
if (hIcon == NULL)
{
if (pSBP->hImage != NULL)
{
::ImageList_Destroy(pSBP->hImage);
}
pSBP->hImage = NULL;
if (bUpdate)
{
InvalidatePaneContent(nIndex);
}
return;
}
ICONINFO iconInfo;
::GetIconInfo(hIcon, &iconInfo);
BITMAP bitmap;
::GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bitmap);
::DeleteObject(iconInfo.hbmColor);
::DeleteObject(iconInfo.hbmMask);
if (pSBP->hImage == NULL)
{
pSBP->cxIcon = bitmap.bmWidth;
pSBP->cyIcon = bitmap.bmHeight;
pSBP->hImage = ::ImageList_Create(pSBP->cxIcon, pSBP->cyIcon, ILC_COLOR32 | ILC_MASK, 1, 0);
::ImageList_AddIcon(pSBP->hImage, hIcon);
RecalcLayout();
}
else
{
ASSERT(pSBP->cxIcon == bitmap.bmWidth);
ASSERT(pSBP->cyIcon == bitmap.bmHeight);
::ImageList_ReplaceIcon(pSBP->hImage, 0, hIcon);
}
if (bUpdate)
{
InvalidatePaneContent(nIndex);
}
}

Use HBITMAP in dll (Logitech SDK)

I'm writing a plugin for the musicplayer named MusicBee. The plugin is for the Logitech G keyboards LCD. For the Logitech G19 keyboards I will add a nice background from a bitmap file.
The sdk says that I must use HBITMAP to create a background. Now I use the HBITMAP and the background ins't showing. This is the code for the background and logo on the main page of the plugin.
m_lcd.ModifyDisplay(LG_COLOR);
background =(HBITMAP) LoadImage( NULL, L"Logitech/G19logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_lcd.SetBackground(background);
logo = m_lcd.AddText(LG_STATIC_TEXT, LG_BIG, DT_CENTER, LGLCD_QVGA_BMP_WIDTH);
m_lcd.SetOrigin(logo, 0, 50);
m_lcd.SetText(logo, _T("MusicBee"));
m_lcd.SetTextFontColor(logo, RGB(0,0,0));
m_lcd.Update();
The full code of my Logitech class:
//-----------------------------------------------------------------
// Logitech File
// C++ Source - Logitech.cpp - version 2012 v1.0
//-----------------------------------------------------------------
//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "stdafx.h"
#include "Logitech.h"
//-----------------------------------------------------------------
// Logitech methods
//-----------------------------------------------------------------
//This LogitechObject is a instance of the Logitech class for using in the thread
Logitech * Logitech::LogitechObject;
Logitech::Logitech(): stopthread(false), firstTime(true), position(0), duration(0)
{
LogitechObject = this;
}
Logitech::~Logitech()
{
stopthread = true;
this->state = StatePlay::Undefined;
timerThread.detach();
}
void CALLBACK Logitech::TimerProc(void* lpParameter, BOOLEAN TimerOrWaitFired)
{
if(LogitechObject->m_lcd.ButtonTriggered(LG_BUTTON_4))
{
LogitechObject->time = 0;
LogitechObject->m_lcd.SetProgressBarPosition(LogitechObject->progressbar, static_cast<FLOAT>(100));
LogitechObject->m_lcd.Update();
}
}
bool Logitech::getFirstTime()
{
return firstTime;
}
//Initialise Logitech LCD
BOOL Logitech::OnInitDialog()
{
HRESULT hRes = m_lcd.Initialize(_T("MusicBee"), LG_DUAL_MODE, FALSE, TRUE);
if (hRes != S_OK)
{
return FALSE;
}
m_lcd.SetAsForeground(true);
//Create home screen Logitech Color LCD
if(m_lcd.IsDeviceAvailable(LG_COLOR))
{
m_lcd.ModifyDisplay(LG_COLOR);
//m_lcd.SetBackground(RGB(245,245,245));
background =(HBITMAP) LoadImage( NULL, L"Logitech/G19logo.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
m_lcd.SetBackground(background);
logo = m_lcd.AddText(LG_STATIC_TEXT, LG_BIG, DT_CENTER, LGLCD_QVGA_BMP_WIDTH);
m_lcd.SetOrigin(logo, 0, 50);
m_lcd.SetText(logo, _T("MusicBee"));
m_lcd.SetTextFontColor(logo, RGB(0,0,0));
m_lcd.Update();
}
//Create home screen Logitech Monochrome LCD
else if(m_lcd.IsDeviceAvailable(LG_MONOCHROME))
{
m_lcd.ModifyDisplay(LG_MONOCHROME);
logo = m_lcd.AddText(LG_STATIC_TEXT, LG_BIG, DT_CENTER, LGLCD_BW_BMP_WIDTH);
m_lcd.SetOrigin(logo, 0, 5);
m_lcd.SetText(logo, _T("MusicBee"));
m_lcd.Update();
}
//Start thread
timerThread = thread(&Logitech::startThread);
//CreateTimerQueueTimer(NULL,NULL,&Logitech::TimerProc,this,0,1250,WT_EXECUTEDEFAULT);
return TRUE; // return TRUE unless you set the focus to a control
}
//Create playing screen for Logitech Monochrome LCD
VOID Logitech::createMonochrome()
{
m_lcd.RemovePage(0);
m_lcd.AddNewPage();
m_lcd.ShowPage(0);
if (logo != 0)
{
delete logo;
logo = 0;
}
artist = m_lcd.AddText(LG_SCROLLING_TEXT, LG_MEDIUM, DT_CENTER, LGLCD_BW_BMP_WIDTH);
m_lcd.SetOrigin(artist, 0, 0);
title = m_lcd.AddText(LG_SCROLLING_TEXT, LG_MEDIUM, DT_CENTER, LGLCD_BW_BMP_WIDTH);
m_lcd.SetOrigin(title, 0, 13);
progressbar = m_lcd.AddProgressBar(LG_FILLED);
m_lcd.SetProgressBarSize(progressbar, 136, 5);
m_lcd.SetOrigin(progressbar, 12, 38);
time = m_lcd.AddText(LG_STATIC_TEXT, LG_SMALL, DT_LEFT, 80);
m_lcd.SetOrigin(time, 12, 29);
time1 = m_lcd.AddText(LG_STATIC_TEXT, LG_SMALL, DT_LEFT, 80);
m_lcd.SetOrigin(time1, 125, 29);
/* playIcon = static_cast<HICON>(LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PNG2), IMAGE_BITMAP, 16, 16, LR_MONOCHROME));
playIconHandle = m_lcd.AddIcon(playIcon, 16, 16);
m_lcd.SetOrigin(playIconHandle, 2, 29);*/
firstTime = false;
changeArtistTitle(this->artistString, this->albumString, this->titleString, this->duration, this->position);
}
//Create playing screen for Logitech Color LCD
VOID Logitech::createColor()
{
m_lcd.RemovePage(0);
m_lcd.AddNewPage();
m_lcd.ShowPage(0);
if (logo != 0)
{
delete logo;
logo = 0;
}
//background.LoadFromResource(NULL, AfxGetInstanceHandle(), IDB_BITMAP2, _T("BMP"));
background =(HBITMAP) LoadImage( NULL, L"Logitech/G19Background.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
//HBITMAP bmpBkg_ = background.GetHBITMAP();
m_lcd.SetBackground(background);
//m_lcd.SetBackground(RGB(184,220,240));
artist = m_lcd.AddText(LG_SCROLLING_TEXT, LG_MEDIUM, DT_CENTER, LGLCD_QVGA_BMP_WIDTH);
m_lcd.SetOrigin(artist, 5, 5);
m_lcd.SetTextFontColor(artist, RGB(0,0,0));
album = m_lcd.AddText(LG_SCROLLING_TEXT, LG_MEDIUM, DT_CENTER, LGLCD_QVGA_BMP_WIDTH);
m_lcd.SetOrigin(album, 5, 30);
m_lcd.SetTextFontColor(album, RGB(0,0,0));
title = m_lcd.AddText(LG_SCROLLING_TEXT, LG_MEDIUM, DT_CENTER, LGLCD_QVGA_BMP_WIDTH);
m_lcd.SetOrigin(title, 5, 55);
m_lcd.SetTextFontColor(title, RGB(0,0,0));
time = m_lcd.AddText(LG_STATIC_TEXT, LG_SMALL, DT_LEFT, 80);
m_lcd.SetOrigin(time, 5, 80);
m_lcd.SetTextFontColor(time, RGB(0,0,0));
time1 = m_lcd.AddText(LG_STATIC_TEXT, LG_SMALL, DT_LEFT, 40);
m_lcd.SetOrigin(time1, 275, 80);
m_lcd.SetTextFontColor(time1, RGB(0,0,0));
progressbar = m_lcd.AddProgressBar(LG_FILLED);//320�240 pixel color screen
m_lcd.SetProgressBarSize(progressbar, 310, 20);
m_lcd.SetProgressBarColors(progressbar, RGB(25,71,94),NULL);
m_lcd.SetOrigin(progressbar, 5, 100);
/*playIcon = static_cast<HICON>(LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_PNG1), IMAGE_ICON, 16, 16, LR_COLOR));
playIconHandle = m_lcd.AddIcon(playIcon, 16, 16);
m_lcd.SetOrigin(playIconHandle, 5, 29);*/
firstTime = false;
changeArtistTitle(this->artistString, this->albumString, this->titleString, this->duration, this->position);
}
void Logitech::startThread()
{
while(!LogitechObject->stopthread)
{
this_thread::sleep_for( chrono::milliseconds(500) );
if(!LogitechObject->stopthread && LogitechObject->progressbar != NULL)
{
//Update progressbar and position time on the screen after 1 second of music.
if(LogitechObject->state == StatePlay::Playing)
{
this_thread::sleep_for( chrono::milliseconds(500) );
LogitechObject->position++;
float progresstime = ((float)LogitechObject->position / (float)LogitechObject->duration)*100;
LogitechObject->m_lcd.SetProgressBarPosition(LogitechObject->progressbar, static_cast<FLOAT>(progresstime));
LogitechObject->m_lcd.SetText(LogitechObject->time, LogitechObject->getTimeString(LogitechObject->position).c_str());
}
//If music stopped then the progressbar and time must stop immediately
else if(LogitechObject->state == StatePlay::Stopped)
{
LogitechObject->position = 0;
LogitechObject->m_lcd.SetProgressBarPosition(LogitechObject->progressbar, 0);
LogitechObject->m_lcd.SetText(LogitechObject->time, LogitechObject->getTimeString(LogitechObject->position).c_str());
}
LogitechObject->m_lcd.Update();
}
}
}
void Logitech::changeArtistTitle(wstring artistStr, wstring albumStr, wstring titleStr, int duration, int position)
{
this->artistString = artistStr;
this->albumString = albumStr;
this->titleString = titleStr;
this->durationString = getTimeString(duration/1000);
this->position = position;
this->duration = duration/1000;
if(!firstTime)
{
if(m_lcd.IsDeviceAvailable(LG_COLOR))
{
m_lcd.SetText(album, albumStr.c_str());
}
m_lcd.SetText(artist, artistStr.c_str());
m_lcd.SetText(title, titleStr.c_str());
m_lcd.SetText(time, getTimeString(position).c_str());
string s( durationString.begin(), durationString.end() );
if(s.size() < 5)
{
s = "0" + s;
}
wstring ws( s.begin(), s.end() );
m_lcd.SetText(time1, ws.c_str());
ws.clear();
///*playIcon = static_cast<HICON>(LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_PNG1), IMAGE_ICON, 16, 16, LR_COLOR));
//playIconHandle = m_lcd.AddIcon(playIcon, 16, 16);
//m_lcd.SetOrigin(playIconHandle, 5, 29);*/
m_lcd.Update();
artistStr.clear();
albumStr.clear();
titleStr.clear();
}
}
//Set current playing position
void Logitech::setPosition(int pos)
{
this->position = pos/1000;
m_lcd.SetText(time, getTimeString(this->position).c_str());
m_lcd.Update();
}
void Logitech::setDuration(int duration)
{
this->duration = duration/1000;
m_lcd.SetText(time1, getTimeString(this->duration).c_str());
m_lcd.Update();
}
//Change play state of the current playing song
void Logitech::changeState(StatePlay state)
{
this->state = state;
if(state == StatePlay::Playing && firstTime)
{
if(m_lcd.IsDeviceAvailable(LG_COLOR))
{
createColor();
}
else if(m_lcd.IsDeviceAvailable(LG_MONOCHROME))
{
createMonochrome();
}
}
}
//Change int of time to string
wstring Logitech::getTimeString(int time)
{
string minutes = to_string((int)time /60);
string seconds = to_string((int)time%60);
if(minutes.size() < 2)
{
minutes = "0" + minutes;
}
if(seconds.size() < 2)
{
seconds = "0" + seconds;
}
string timeString = minutes + ":" + seconds;
return wstring( timeString.begin(), timeString.end() );
}
What is the problem that the background nog showing?
From your reply in the comments, it seems the problem is with the LoadImage call, so we can ignore the rest of the code for now. Call GetLastError right after the LoadImage call fails and see what it returns.
Only be a few things can go wrong with a LoadImage call like that:
You could have the file name wrong. (GetLastError will return ERROR_FILE_NOT_FOUND)
You're using a relative path, but maybe the current working directory isn't where you think it is. (GetLastError will return ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND.)
Maybe that API doesn't work with slashes in place of backslashes.
Maybe you don't have access to read the file. (GetLastError will return ERROR_ACCESS_DENIED or ERROR_NETWORK_ACCESS_DENIED.)
Maybe another application has the file open without sharing. (GetLastError will return ERROR_SHARING_VIOLATION.)
Maybe the file isn't a valid bitmap. (I'm not sure what GetLastError will return here. Perhaps something like ERROR_INVALID_PARAMETER.)
Maybe it's a gigantic bitmap and there's not enough memory to load it. (GetLastError will return ERROR_NOT_ENOUGH_MEMORY.)
In general, when debugging, isolate the point in the code where things go bad (once you know LoadImage failed, you can stop worrying about all the code that happens after that). Then get as much information as you can (e.g., if it's a Windows API call that failed, call GetLastError and re-read the entire MSDN page for that API, use a debugger to examine the relative state at that point). From there, it will usually be pretty obvious what to do. If not, write the simplest program you can that does the same step. If it works, study the differences between your simple example and your actual code.