reading from ComboBox - c++

how can i read the text of a selected value of a comboBox in windows aplication(borland C++) for example:
i have combobox which contains 2 values (sum and mult) i want to see if it is sum i have to add the numbers and if it mult i have to multiplicate the numbers so how can i read the value of combobox in this case.

For Windows:
In your window procedure use the WM_COMMAND message and then check for a CBN_SELCHANGE notification. Then use WM_GETTEXT along with WM_GETTEXTLENGTH to receive the selected text like Mark Ingram says. Or you can also use CB_GETCURSEL to receive the identifier of the selected item.
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDC_COMBO:
if (HIWORD(wParam) == CBN_SELCHANGE) {
HWND hCtl = GetDlgItem(hWnd, IDC_COMBO);//Get handle for HMENU item
if (SendMessage(hCtl, CB_GETCURSEL, 0, 0) == compareValue) {
//...
}
}
break;
}
break;
//...
}
}

Assuming that you are using Windows, you can use the following messages:
WM_GETTEXTLENGTH and WM_GETTEXT.
Firstly, get the length of the selected text, then allocate your buffer to ensure it's large enough, then retrieve the actual text. Easy.
Example:
const UINT length = ::SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0);
LPTSTR pszText = new TCHAR[length + 1];
::SendMessage(hWnd, WM_GETTEXT, length + 1, pszText);
// pszText will now contain the text you want, do what you want with it
delete[] pszText; // Remember to delete else you will leak.

I never work with c++ with winapplication but i tried it with the c# and hopefully that you want the desired output as i got through your question if it is not right then you should edit your question.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.Text == "ADD")
{
int a = 12, b = 13, c;
c = a + b;
MessageBox.Show("Result of adding= " + c);
}
else if (comboBox1.Text == "Multiple")
{
int x = 3, y = 5, z;
z = x * y;
MessageBox.Show("Result of multiplication= " + z);
}
}

Related

Windows API: Guess the next caret position

I'm currently writing a function to get the current line/column of an EDIT control, and I'm stuck on a problem:
If I use WM_KEYUP to handle the caret position, the coordinates are valid but it can't be updated every "frame" since it waits for the user to release the pressed key
If I use WM_KEYDOWN, GetCaretPos returns the "previous" position of the caret (well, it's an obvious issue since it hasn't moved yet.)
Is there anything I can do to guess the next position of a caret? is it efficient if I just use EM_GETSEL?
LRESULT Edit::HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_LBUTTONDOWN:
{
// Get character position from the mouse cursor's position (currently, there's no conversion of the coordinates if the mouse cursor is out of bound)
POINT pntMousePos{ 0 };
pntMousePos.x = GET_X_LPARAM(lParam);
pntMousePos.y = GET_Y_LPARAM(lParam);
LRESULT notifyValue = this->Notify(EM_CHARFROMPOS, 0, MAKELPARAM(pntMousePos.x, pntMousePos.y));
int lineIdx = static_cast<int>(this->Notify<int, LPARAM>(EM_LINEINDEX, -1));
if (lineIdx == NULL) {
DWORD beg, end;
lineIdx = Notify(EM_GETSEL, &beg, &end);
}
m_caretPos.line = HIWORD(notifyValue) + 1;
m_caretPos.column = (LOWORD(notifyValue) - lineIdx) + 1;
// Send a custom message to the main window
SendMessage(GetParent(m_parent) /*The EDIT control is actually a child of a tab control that is itself a child of the main window, ignore this */, CEM_GETLINEINFO, MAKEWPARAM(m_caretPos.line, m_caretPos.column), 0);
}
break;
case WM_KEYDOWN:
{
// Get Character position from the carret's position
// Get text metric (doesn't work so I removed some lines)
TEXTMETRIC tm{0};
HDC hdc = GetDC(m_self);
SelectObject(hdc, this->m_fnt);
GetTextMetricsW(hdc, &tm);
ReleaseDC(m_self, hdc);
POINT caretPos{ 0 };
GetCaretPos(&caretPos);
LRESULT notifyValue = this->Notify(EM_CHARFROMPOS, 0, MAKELPARAM(caretPos.x, caretPos.y));
int lineIdx = static_cast<int>(this->Notify<int, LPARAM>(EM_LINEINDEX, -1));
m_caretPos.line = HIWORD(notifyValue) + 1;
m_caretPos.column = (LOWORD(notifyValue) - lineIdx) + 1;
SendMessage(GetParent(m_parent), CEM_GETLINEINFO, MAKEWPARAM(m_caretPos.line, m_caretPos.column), 0);
}
break;
}
return DefSubclassProc(m_self, msg, wParam, lParam);
}

Detect when any application Window is dragged to top of screen

On Windows 10 I have been experimenting with replacing the "Window snap" feature to work better with ultra wide monitors. While I have had no problem capturing the Windows Key+arrow cursors to handle the keyboard shortcut, I now want to detect when another application Window has been dragged to the top/right/left/bottom of the current monitor.
Current code:
#include <iostream>
#include <Windows.h>
HHOOK _hook_keyboard;
KBDLLHOOKSTRUCT kbdStruct;
CONST int HORIZONTAL_SLOTS = 4;
CONST int VERTICAL_SLOTS = 1;
// horizontalPosition/verticalPosition specifies which "slot" starting at 0 to place Window in
// horizontalSlots/verticalSlots specifies how many slots to divide the screen into
void MoveAndResizeActiveWindow(int horizontalPosition, int verticalPosition, int horizontalSlots, int verticalSlots)
{
// get work area on primary monitor
HWND currentWindow = GetForegroundWindow();
if (currentWindow != NULL)
{
HMONITOR currentMonitor = MonitorFromWindow(currentWindow, MONITOR_DEFAULTTONEAREST);
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfo(currentMonitor, &monitorInfo))
{
long width = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
long height = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
long snappedWidth = width / horizontalSlots;
long snappedHeight = height / verticalSlots;
long snappedLeft = (snappedWidth * horizontalPosition) + monitorInfo.rcWork.left;
long snappedTop = (snappedHeight * verticalPosition) + monitorInfo.rcWork.top;
MoveWindow(currentWindow, snappedLeft, snappedTop, snappedWidth, snappedHeight, true);
}
}
}
LRESULT __stdcall HookCallbackKeyboard(int nCode, WPARAM wParam, LPARAM lParam)
{
BOOL bEatkeystroke = false;
short keyState;
if (nCode >= 0)
{
kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
switch (wParam)
{
case WM_KEYDOWN:
keyState = GetAsyncKeyState(VK_LWIN);
if (keyState)
{
switch (kbdStruct.vkCode)
{
case VK_LEFT:
bEatkeystroke = true;
break;
case VK_RIGHT:
bEatkeystroke = true;
break;
case VK_UP:
bEatkeystroke = true;
break;
case VK_DOWN:
bEatkeystroke = true;
break;
};
};
break;
case WM_KEYUP:
keyState = GetAsyncKeyState(VK_LWIN);
if (keyState)
{
switch (kbdStruct.vkCode)
{
case VK_LEFT:
MoveAndResizeActiveWindow(0, 0, 4, 1);
bEatkeystroke = true;
break;
case VK_RIGHT:
MoveAndResizeActiveWindow(3, 0, 4, 1);
bEatkeystroke = true;
break;
break;
case VK_UP:
MoveAndResizeActiveWindow(1, 0, 4, 1);
bEatkeystroke = true;
break;
case VK_DOWN:
MoveAndResizeActiveWindow(2, 0, 4, 1);
bEatkeystroke = true;
break;
};
}
break;
};
}
if (bEatkeystroke)
{
return 1;
}
else
{
return CallNextHookEx(_hook_keyboard, nCode, wParam, lParam);
}
}
void SetHook()
{
if (!(_hook_keyboard = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallbackKeyboard, NULL, 0)))
{
MessageBox(NULL, L"Failed to install hook on keyboard!", L"Error", MB_ICONERROR);
}
}
int main(int argc, char** argv[])
{
SetHook();
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Any suggestions how to identify when Windows have been dragged to a particular location on the screen?
As per advice in replies to original question I have tried used SetWinEventHook with the following code, planning to restrict EVENT_MIN and EVENT_MAX once correct events to watch for worked out.
g_hook_winevent = SetWinEventHook(
EVENT_MIN, EVENT_MAX,
NULL, // Handle to DLL.
HandleWinEvent, // The callback.
0, 0, // Process and thread IDs of interest (0 = all)
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); // Flags.
}
void CALLBACK HandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd,
LONG idObject, LONG idChild,
DWORD dwEventThread, DWORD dwmsEventTime)
{
// process event here
}
While this easily tracks start or end of a Windows move with EVENT_SYSTEM_MOVESIZESTART and EVENT_SYSTEM_MOVESIZEEND I can't see an event here that tracks the moving of Window prior to EVENT_SYSTEM_MOVESIZEEND.
While that will work if only good option, ideally I want to be able to detect Window location from start of EVENT_SYSTEM_MOVESIZESTART until EVENT_SYSTEM_MOVESIZEEND completes. Testing with notepad the only event getting raised during the move is EVENT_OBJECT_NAMECHANGE, which seems to constantly trigger during Window move, at least with Notepad. However based on description in documentation I'm not sure if this is suitable for my use case: "An object's Name property has changed. The system sends this event for the following user interface elements: check box, cursor, list-view control, push button, radio button, status bar control, tree view control, and window object. Server applications send this event for their accessible objects."

Display formatted text on selecting item in the Combobox

I have a combobox in that I want to display different string on selecting an item in Combo.
My combo box is a dropdown combobox.
For eg: I have following in my combobox.
Alex - Manager
Rain - Project Lead
Shiney - Engineer
Meera - Senior Engineer
OnSelecting an item in combobox I want to diaply only name i.e. Alex.
I tried below code
struct details{
CString name;
CString des;
};
BOOL CComboTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
details d1;
d1.name = _T("alex");
d1.des =_T("manager");
m_vec.push_back(d1);
details d2;
d2.name = _T("Rain");
d2.des =_T("Engineer");
m_vec.push_back(d2);
// TODO: Add extra initialization here
for(int i=0;i<m_vec.size();i++)
{
m_ctrlCombo.AddString(m_vec[i].name+m_vec[i].des);
m_ctrlCombo.SetItemData(i,(DWORD_PTR)&m_vec[i]);
}
m_ctrlCombo.SelectString(-1,m_vec[0].name);
m_ctrlCombo.SetWindowText(m_vec[0].name);
return TRUE; // return TRUE unless you set the focus to a control
}
void CComboTestDlg::OnCbnSelchangeCombo1()
{
int nItem = m_ctrlCombo.GetCurSel();
details* det = (details*)m_ctrlCombo.GetItemData(nItem);
PostMessage(SETCOMBOTEXT,IDC_COMBO1,(LPARAM)(LPCTSTR)det->name);
}
BOOL CComboTestDlg::PreTranslateMessage(MSG* pMsg)
{
MSG msg1=*pMsg;//I am loosing the value after checking ..so storing temp.
MSG msg;
CopyMemory(&msg, pMsg, sizeof(MSG));
HWND hWndParent = ::GetParent(msg.hwnd);
while (hWndParent && hWndParent != this->m_hWnd)
{
msg.hwnd = hWndParent;
hWndParent = ::GetParent(hWndParent);
}
if (pMsg->message==SETCOMBOTEXT && (pMsg->wParam == IDC_COMBO1))
SetDlgItemText(IDC_COMBO1, (LPCTSTR)pMsg->lParam);
if(pMsg->message==WM_KEYDOWN)
{
if(pMsg->wParam==VK_RETURN && msg.hwnd ==m_ctrlCombo.m_hWnd )
{
OnCbnSelchangeCombo1();
}
}
return CDialog::PreTranslateMessage(pMsg);
}
I am able to achieve my requirement OnComboSelChange() and Arrow Keys event but on pressing enter key after using arrow keys in combo box, it is not showing formatted text in combo box.
I think the most reliable and easy to implement solution is to subclass the edit control of the combobox. Intercept the WM_SETTEXT message and change the text as you like before forwarding it to the rest of the chain (finally the original window proc).
Install the sub class proc in OnInitDialog():
COMBOBOXINFO cbi{ sizeof(cbi) };
if( m_ctrlCombo.GetComboBoxInfo( &cbi ) )
{
SetWindowSubclass( cbi.hwndItem, ComboEditSubClassProc, 0, 0 );
}
ComboEditSubClassProc() could look like this:
LRESULT CALLBACK ComboEditSubClassProc( HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
switch( uMsg )
{
case WM_SETTEXT:
{
CString text = reinterpret_cast<LPCTSTR>( lParam );
// Extract the name (everything before "-").
CString name = text.SpanExcluding( _T("-") );
name.TrimRight();
// Forward the modified text to any other sub class procs, aswell
// as the original window proc at the end of the chain.
return DefSubclassProc( hWnd, uMsg, 0, reinterpret_cast<LPARAM>( name.GetString() ) );
}
case WM_NCDESTROY:
{
// We must remove our subclass before the subclassed window gets destroyed.
// This message is our last chance to do that.
RemoveWindowSubclass( hWnd, ComboEditSubClassProc, uIdSubclass );
break;
}
}
return DefSubclassProc( hWnd, uMsg, wParam, lParam );
}
Notes:
Contrary to my original solution of processing CBN_SELCHANGE, the current solution also works correctly if the combobox drop-down list is closed by pressing Return or is dismissed.
I think it is in general more reliable because we don't have to rely on the order of the notifications. The combobox has to finally call WM_SETTEXT to change the content of the edit control so this message will always be received.
There will also be no flickering as in the original solution where the text was first changed by the combobox and then modified by our code only after the fact.

GetWindowText() doesn't work

Initially I have to say that I know nothing about WinAPI. I'm learning from quite old tutorial, which seems to be a little bit outdated. I'm trying to make a dialog box where user would type in size of a next window. I've made it in Visual Studio using Resource Editor (or whatever it is called). I'm trying to retrieve data from Edit Controls, but GetWindowText doesn't work well.
So I made global LPTSTR named SizeX and SizeY (I know I could made them local and later pass them to a function that creates the second window, but I've got then problems with hInstance... nevermind).
BOOL CALLBACK SettingsProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
{
SetWindowTextA(GetDlgItem(hwnd, IDC_EDIT1), "20"); //I'm setting default input in case the user doesn't want to write anything
SetWindowTextA(GetDlgItem(hwnd, IDC_EDIT2), "20");
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_BUTTON1:
{
GetWindowText(GetDlgItem(hwnd, IDC_EDIT1), sizeX, GetWindowTextLength(GetDlgItem(hwnd, IDC_EDIT1)) + 1);
if (sizeX == NULL)
break; //breaks every time
GetWindowText(GetDlgItem(hwnd, IDC_EDIT2), sizeY, 10);
EndDialog(hwnd, IDC_BUTTON1);
}
break;
}
}
break;
default: return FALSE;
}
return TRUE;
}
I'm sure I have a lot of basic mistakes in this code, so please don't blame me :P
I have no idea how to make it work. The fantastic tutorial I use tells nothing about Edit Controls, it even has an information that it might be too old. Unfortunately that is the only WinAPI tutorial I've found in my language, if you know any good one in English I'd be glad.
the thing that you should do is use directly GetDlgItemInt to retrieve sizeX and sizeY otherwise you should get text as a string then convert it into int:
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_BUTTON1:
{
BOOL bCheck = FALSE;
sizeX = GetDlgItemInt(hwnd, IDC_EDIT1, &bCheck, false);
sizeY = GetDlgItemInt(hwnd, IDC_EDIT2, &bCheck, false);
// or text then convert:
int textLengthX = SendDlgItemMessage(hwnd, IDC_EDIT1, WM_GETTEXTLENGTH, 0, 0);
int textLengthY = SendDlgItemMessage(hwnd, IDC_EDIT2, WM_GETTEXTLENGTH, 0, 0);
LPSTR lpTextX = (LPSTR)GlobalAlloc(GPTR, textLengthX + 1);
LPSTR lpTextY = (LPSTR)GlobalAlloc(GPTR, textLengthY + 1);
SendDlgItemMessage(hwnd, IDC_EDIT1, WM_GETTEXT, (WPARAM)textLengthX + 1, (LPARAM)lpTextX);
SendDlgItemMessage(hwnd, IDC_EDIT1, WM_GETTEXT, (WPARAM)textLengthY + 1, (LPARAM)lpTextY);
// now you have sizeX and sizeY as strings so convert them to int:
int sizeX = atoi(lpTextX);
int sizeY = atoi(lpTextY);
GlobalFree(lpTextX);
GlobalFree(lpTextY);
}
break;
}
break;
}

Arrow keypress not working

This are my code hope any kind souls will be kind enough to help me.
Other Keys like Alphabets or Home or PgUp etc.. is working. Except for all the arrows.
void AutoMove (HWND hWnd)
{
BOOL bWorked = FALSE;
int value = 0;
LPARAM lparam = (MapVirtualKey(0x025, 0) << 16) + 1; //Send to graphic screen
HWND MSHWND = FindWindow ("MapleStoryClass",0); //Find class window
value = GetDlgItemInt(hWnd, IDC_GETAUTOMOVE, &bWorked, 0);
SetDlgItemText(hWnd, IDC_AUTOMOVE, "On" ); //"On" message
while (!AutoMoveExit)
{
PM(MSHWND, WM_KEYDOWN, 0x025, lparam); //Send Left Arrow Key
Sleep (1000);
PM(MSHWND, WM_KEYUP, 0x025, NULL);
Sleep (value);
}
SetDlgItemText(hWnd, IDC_AUTOMOVE, "Off" ); //"Off" Message
}
Not tested yet, but you can try ignoring the lParam value like this:
PostMessage(MSHWND, WM_KEYDOWN, VK_LEFT, 0)