Страница 1 из 2

Работа со списком в WinAPI.

Добавлено: 20 май 2008, 18:28
Apokal
Нада было написать програму суть которой заключаетса в том что создавалось окно, в нем два списка которые заполнены информацией ( в даном случае Государства в первом списке и их Столицы во втором), а также две кнопки ">>" и "<<", при нажатии на кнопку ">>" выдаетса сообщение что нажата кнопка ">>", при нажатии на кнопку "<<" выдаетса сообщение что нажата кнопка "<<", при выделении сторки в 1-ом или 2-ом списке выдаетса сообщение с текстом выделеной строки.

Вот код:

Код: Выделить всё

#include <windows.h>
#define ID_BUTTON1 1001
#define ID_BUTTON2 1002
#define ID_LISTBOX1 1003
#define ID_LISTBOX2 1004

BOOL RegClass(WNDPROC,LPCTSTR,UINT);
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE hInstance;
char szClassName[]="Class1";


int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int nCmdShow)
{
	MSG msg; HWND hwnd; hInstance=hInst;
	if(!RegClass(WndProc,szClassName,COLOR_WINDOW))
		return FALSE;
	hwnd=CreateWindow(szClassName,"Laboratory_Work_#14",
		WS_OVERLAPPEDWINDOW|WS_VISIBLE,340,252,600,300,
		0,0,hInstance,NULL);
	if(!hwnd) return FALSE;
	while(GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
	return msg.wParam;
}

BOOL RegClass(WNDPROC Proc,LPCTSTR szName, UINT brBakcground)
{
	WNDCLASS wc; wc.style=wc.cbClsExtra=wc.cbWndExtra=0;
	wc.lpfnWndProc=Proc; wc.hInstance=hInstance;
	wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wc.hCursor=LoadCursor(NULL,IDC_ARROW);
	wc.hbrBackground=(HBRUSH)(GetStockObject(WHITE_BRUSH));
	wc.lpszMenuName=(LPCTSTR)NULL;
	wc.lpszClassName=szName;
	return (RegisterClass(&wc)!=0);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static HWND hButton1,hButton2,hListBox1,hListBox2; RECT Rect;
	char Buf1[]="Russia",Buf2[]="Ukraine",Buf3[]="U.S.A",Buf4[]="France",Buf5[]="Germany",
	Buf6[]="Moscow",Buf7[]="Kiev",Buf8[]="Washington",Buf9[]="Paris",Buf10[]="Berlin",Buf[10];
    int ListItem1=NULL,ListItem2=NULL;

	switch(msg)
	{	
		case WM_CREATE:
		{	
			GetClientRect(hwnd,&Rect);
			hListBox1=CreateWindow("listbox",NULL,WS_CHILD|WS_VISIBLE|LBS_STANDARD,
			Rect.left+50,Rect.top+50,200,150,hwnd,(HMENU)ID_LISTBOX1,hInstance,NULL);
			SendMessage(hListBox1,LB_ADDSTRING,0,(LPARAM)Buf1);
			SendMessage(hListBox1,LB_ADDSTRING,0,(LPARAM)Buf2);
			SendMessage(hListBox1,LB_ADDSTRING,0,(LPARAM)Buf3);
			SendMessage(hListBox1,LB_ADDSTRING,0,(LPARAM)Buf4);
			SendMessage(hListBox1,LB_ADDSTRING,0,(LPARAM)Buf5);
			hListBox2=CreateWindow("listbox",NULL,WS_CHILD|WS_VISIBLE|LBS_STANDARD,
			Rect.left+350,Rect.top+50,200,150,hwnd,(HMENU)ID_LISTBOX2,hInstance,NULL);
			SendMessage(hListBox2,LB_ADDSTRING,0,(LPARAM)Buf6);
			SendMessage(hListBox2,LB_ADDSTRING,0,(LPARAM)Buf7);
			SendMessage(hListBox2,LB_ADDSTRING,0,(LPARAM)Buf8);
			SendMessage(hListBox2,LB_ADDSTRING,0,(LPARAM)Buf9);
			SendMessage(hListBox2,LB_ADDSTRING,0,(LPARAM)Buf10);

			
			hButton1=CreateWindow("button",">>",
			WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
			Rect.left+50,Rect.top+205,200,50,hwnd,(HMENU)ID_BUTTON1,hInstance,NULL);
			hButton2=CreateWindow("button","<<",
			WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,Rect.top+350,Rect.top+205,200,50,hwnd,
			(HMENU)ID_BUTTON2,hInstance,NULL);
			return 0;
		}
		case WM_COMMAND:
		{
			switch(LOWORD(wParam))
			{
				case ID_LISTBOX1:
				{
					
						if(HIWORD(wParam)==LBN_DBLCLK)
						{
							ListItem1=(int)SendMessage(hListBox1,LB_GETCURSEL,0,0);
							if(ListItem1!=LB_ERR)
								SendMessage(hListBox1,LB_GETTEXT,ListItem1,(LPARAM)Buf);
								MessageBox(hwnd,Buf,"ListBox1",MB_OK);
							return 0;
						}
					
				}

				case ID_LISTBOX2:
				{
					
						if(HIWORD(wParam)==LBN_DBLCLK)
						{
							     ListItem1=(int)SendMessage  (hListBox2,LB_GETCURSEL,0,0);
							if(ListItem1!=LB_ERR)
								SendMessage(hListBox2,LB_GETTEXT,ListItem1,(LPARAM)Buf);
								MessageBox(hwnd,Buf,"ListBox2",MB_OK);
							return 0;
						}
				}
				
				case ID_BUTTON1:
				{
					MessageBox(hwnd,"Button >> is pressed","Button >>",MB_OK);
					
					return 0;
				}
				case ID_BUTTON2:
				{
					MessageBox(hwnd,"Button << is pressed","Button <<",MB_OK);

					return 0;
				}
			}
			return 0;
			
		}
		case WM_DESTROY:{PostQuitMessage(0); return 0;}
	}
	return DefWindowProc(hwnd,msg,wParam,lParam);
}

ListItem1,ListItem2 переменные хранящие номер выделеной строки соответствено первого и второго списков.
При запуске все создаетса, списки заполняютса...
Но 1) Почему списки запалняютса хаотично, а не в том порядке в котором я заношу туда названия.Тобиш по идее должно ити Russia-Ukraine-USA-France-Paris-Germany а выходит USA-France-Russia-Germany-Ukraine/
2) При двойном клике на строке спика№1 или строке списка№2 должно выскочить окно с текстом в строке, а выскакует два окна с надписью "Button >> is pressed"(((
Тобиш вместо того шоб обрабатывать сообения от списков обрабатываетса кнопка ">>". помогите плиз.

Re: Работа со списком в WinAPI.

Добавлено: 20 май 2008, 18:57
WinMain
Чтобы строки в списке отображались в том порядке, в котором ты их туда записываешь, нужно отключить у LISTBOX-ов свойство Sort. По умолчанию оно имеет значение TRUE, поэтому строки отсортированы в алфавитном порядке с учётом регистра букв.

Re: Работа со списком в WinAPI.

Добавлено: 20 май 2008, 19:03
Apokal
Пасиб за ответ. А насчет второго вопроса.... какие могут быть причины?

Re: Работа со списком в WinAPI.

Добавлено: 20 май 2008, 19:51
Albor
По 2-му вопросу: попробуй поставить оператор break после case, тогда следующий case точно не выполнится(или я не так понял и case, отвечающий за двойной клик, вообще не отрабатывает?). А по первой части - всётаки удобнее когда список отсортирован. В списках можно к каждому итему прикреплять целочисленные данные, поэтому, если закрепить за страной и столицей одинаковое число (так сказать - связать списки), то можно работать более красиво.

Re: Работа со списком в WinAPI.

Добавлено: 20 май 2008, 20:24
Romeo
В конце каждого case поставь break. Тогда ты сможешь кликнуть второй раз по элементу списка.

В данный момент происходит следующее:

- Ты кликаешь по элементу списка первый раз
- WndProc сразу же вызывается с нотификацией LBN_SELCHANGE
- В обработчике проверяется условие HIWORD(wParam)==LBN_DBLCLK - оно ложно и код внутри не выполняется
- Так, как перед завешающим }, который принадлежит case отсутствует break, выполнение продолжается со строки MessageBox(hwnd,"Button >> is pressed","Button >>",MB_OK);

Re: Работа со списком в WinAPI.

Добавлено: 20 май 2008, 20:56
Apokal
Я в начале не полностью раскрыл назначение этой програмы... Кнопки ">>" и "<<" предназначались для того чтобы переместить строку из списка№1 в список№2 и из списка№2 в список№1 соответствино. Предыдущий код как бы был основой, но поскоку он неработал я дальше кодить перестал.

Большое спасибо Albor'y break помог. Но также я заметил что еси вместо switch и case (выделеные жирным) ставить if() то эфект тот же, тобиш :
Вместо

Код: Выделить всё

case WM_COMMAND:
		{
			[B]switch(LOWORD(wParam))[/B]
			{
				[B]case ID_LISTBOX1:[/B]
				{
					
						if(HIWORD(wParam)==LBN_DBLCLK)
						{
							ListItem1=(int)SendMessage(hListBox1,LB_GETCURSEL,0,0);
							if(ListItem1!=LB_ERR)
								SendMessage(hListBox1,LB_GETTEXT,ListItem1,(LPARAM)Buf);
								MessageBox(hwnd,Buf,"ListBox1",MB_OK);
							return 0;
						}
					
				}break;

				[B]case ID_LISTBOX2:[/B]
				{
					
						if(HIWORD(wParam)==LBN_DBLCLK)
						{
							ListItem2=(int)SendMessage(hListBox2,LB_GETCURSEL,0,0);
							if(ListItem1!=LB_ERR)
								SendMessage(hListBox2,LB_GETTEXT,ListItem2,(LPARAM)Buf);
								MessageBox(hwnd,Buf,"ListBox2",MB_OK);
							return 0;
						}
				}break;
				
				[B]case ID_BUTTON1:[/B]
				{
					
					SendMessage(hListBox1,LB_GETTEXT,ListItem1,(LPARAM)Buf);
					SendMessage(hListBox2,LB_ADDSTRING,0,(LPARAM)Buf);
					SendMessage(hListBox1,LB_DELETESTRING,ListItem1,0);
					
					
					return 0;
				}break;
				[B]case ID_BUTTON2:[/B]
				{
					SendMessage(hListBox2,LB_GETTEXT,ListItem2,(LPARAM)Buf);
					SendMessage(hListBox1,LB_ADDSTRING,0,(LPARAM)Buf);
					SendMessage(hListBox2,LB_DELETESTRING,ListItem2,0);

					return 0;
				}break;
			}
			return 0;
Это изменная часть кода, уже для проги которая бужет перествлять строки (это навсякий случай если у когото будет подобная проблема).
Выйдет так:

Код: Выделить всё

case WM_COMMAND:
		{
			if(LOWORD(wParam)==ID_LISTBOX1)
				if(HIWORD(wParam)==LBN_DBLCLK)
				{
							ListItem1=(int)SendMessage(hListBox1,LB_GETCURSEL,0,0);
							if(ListItem1!=LB_ERR)
								SendMessage(hListBox1,LB_GETTEXT,ListItem1,(LPARAM)Buf);
								MessageBox(hwnd,Buf,"ListBox1",MB_OK);
							return 0;
				}
									
			if(LOWORD(wParam)==ID_LISTBOX2)
	                        if(HIWORD(wParam)==LBN_DBLCLK)
				{
							ListItem2=(int)SendMessage(hListBox2,LB_GETCURSEL,0,0);
							if(ListItem1!=LB_ERR)
								SendMessage(hListBox2,LB_GETTEXT,ListItem2,(LPARAM)Buf);
								MessageBox(hwnd,Buf,"ListBox2",MB_OK);
							return 0;
				}
				
				if(LOWORD(wParam)==ID_BUTTON1)
				{
					
					SendMessage(hListBox1,LB_GETTEXT,ListItem1,(LPARAM)Buf);
					SendMessage(hListBox2,LB_ADDSTRING,0,(LPARAM)Buf);
					SendMessage(hListBox1,LB_DELETESTRING,ListItem1,0);
					
					
					return 0;
				}
				if(LOWORD(wParam)==ID_BUTTON2)
				{
					SendMessage(hListBox2,LB_GETTEXT,ListItem2,(LPARAM)Buf);
					SendMessage(hListBox1,LB_ADDSTRING,0,(LPARAM)Buf);
					SendMessage(hListBox2,LB_DELETESTRING,ListItem2,0);

					return 0;
				}
			}
			return 0;
Также слудет перед определением ListItem1,ListTem2 поставить static.
Вообщем после изменений с помошью break или if() прога заработала.

Спасибо что помогли.

Re: Работа со списком в WinAPI.

Добавлено: 20 май 2008, 21:29
Romeo
Смотри выше, я объяснил почему работало именно так, а не иначе. Относительно if тоже могу объяснить почему работает именно так. Всё потому, что при переводе на if ты сделал ту же самую ошибку. Для case ты забыл break, а для if - else. Правильная структура кода, использующая if должна выглядеть так:

Код: Выделить всё

if (...)
{
   ...
}
else if (...)
{
   ...
}
else if (...)
{
   ...
}

Re: Работа со списком в WinAPI.

Добавлено: 20 май 2008, 22:49
Apokal
Спасибо. Терь все понятно.

П.С. Подскажыте плиз де в нете мона прочитать про создание меню с помощью файла ресурсов, а то с помощью WinAPI уже знаком а вот про способ с помощью файла ресурсов нечего незнаю.

Re: Работа со списком в WinAPI.

Добавлено: 21 май 2008, 00:26
Apokal
Ещо один вопросик но уже не по спискам а по меню, написал тут бо нехотел новый топ создавать:
Вообщем прога должна создавать окно с меню в котором есть елемент "Users". при нажатии на который будет появлятса вспливающиеся меню с тремя елементами "User1","User2","User3".

Код:

Код: Выделить всё

#include <windows.h>
#define CM_USERS_USER1 1001
#define CM_USERS_USER2 1002
#define CM_USERS_USER3 1003

BOOL RegClass(WNDPROC,LPCTSTR,UINT);
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE hInstance;
char szClassName[]="Class1";


int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int nCmdShow)
{
	MSG msg; HWND hwnd; hInstance=hInst;
	if(!RegClass(WndProc,szClassName,COLOR_WINDOW))
		return FALSE;
	hwnd=CreateWindow(szClassName,"Laboratory_work_#15",
		WS_OVERLAPPEDWINDOW|WS_VISIBLE,340,212,600,600,
		0,0,hInstance,NULL);
	if(!hwnd) return FALSE;
	while(GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
	return msg.wParam;
}

BOOL RegClass(WNDPROC Proc,LPCTSTR szName, UINT brBakcground)
{
	WNDCLASS wc; wc.style=wc.cbClsExtra=wc.cbWndExtra=0;
	wc.lpfnWndProc=Proc; wc.hInstance=hInstance;
	wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wc.hCursor=LoadCursor(NULL,IDC_ARROW);
	wc.hbrBackground=(HBRUSH)(GetStockObject(BLACK_BRUSH));
	wc.lpszMenuName=(LPCTSTR)NULL;
	wc.lpszClassName=szName;
	return (RegisterClass(&wc)!=0);
}

BOOL SetMenuItem(HMENU hMenu,UINT uIns,UINT fState,BOOL flag)
{
	MENUITEMINFO mii; mii.cbSize=sizeof(MENUITEMINFO);
	mii.fMask=MIIM_STATE|MIIM_ID;
	mii.fState=fState; mii.wID=uIns;
	return SetMenuItemInfo(hMenu,uIns,flag,&mii);
}

UINT GetMenuItem(HMENU hMenu,UINT uIns,BOOL flag)
{
	MENUITEMINFO mii; mii.cbSize=sizeof(MENUITEMINFO);
	mii.fMask=MIIM_STATE;
	GetMenuItemInfo(hMenu,uIns,flag,&mii);
	return mii.fState;
}

BOOL CreateMenuItem(HMENU hMenu, char *str,UINT uIns,UINT uCom,HMENU hSubMenu, BOOL flag, UINT fType)
{
	MENUITEMINFO mii; mii.cbSize=sizeof(MENUITEMINFO);
	mii.fMask=MIIM_STATE|MIIM_TYPE|MIIM_SUBMENU|MIIM_ID;
	mii.fType=fType; mii.fState=MFS_ENABLED;
	mii.dwTypeData=str; mii.cch=sizeof(str);
	mii.wID=uCom; mii.hSubMenu=hSubMenu;
	return InsertMenuItem(hMenu,uIns,flag,&mii);
}

LRESULT CALLBACK WndProc(HWND jwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static HMENU hMainMenu,hUsersMenu;
	switch(msg)
	{
		case WM_CREATE:
		{
			hMainMenu=CreateMenu();
			hUsersMenu=CreatePopupMenu();
			int i=0;
			CreateMenuItem(hUsersMenu,"&User1",i++,CM_USERS_USER1,NULL,FALSE,MFT_STRING);
			CreateMenuItem(hUsersMenu,"&User2",i++,CM_USERS_USER2,NULL,FALSE,MFT_STRING);
			CreateMenuItem(hUsersMenu,"&User3",i++,CM_USERS_USER3,NULL,FALSE,MFT_STRING);
			i=0;
			CreateMenuItem(hMainMenu,"&UsersMenu",i++,0,hUsersMenu,FALSE,MFT_STRING);
			SetMenu([B]hwnd[/B],hMainMenu);// здесь тот hwnd который глючит
			DrawMenuBar(hwnd);
			return 0;
		}

		case WM_DESTROY:
		{
			DestroyMenu(hUsersMenu);
			PostQuitMessage(0);
			return 0;
		}
	}
	return DefWindowProc(hwnd,msg,wParam,lParam);
}
Все норм но вот при компиляции выдает error C2065: 'hwnd' : undeclared identifier. И показует на hwnd который в коде выделенный жырным. Старнно ведь он обьявлен выше в WinMain и WndProc должна его видеть, тем более на DrawMenu(hwnd) ошыбку компилятор невыдает))))

hwnd и jwnd

Добавлено: 21 май 2008, 10:05
BBB
Apokal писал(а):Все норм но вот при компиляции выдает error C2065: 'hwnd' : undeclared identifier. И показует на hwnd который в коде выделенный жырным. Старнно ведь он обьявлен выше в WinMain и WndProc должна его видеть, тем более на DrawMenu(hwnd) ошибку компилятор невыдает))))


У тебя опечатка. Ибо в заголовке пр-ры WndProc первый параметр назван jwnd, а не hwnd:

Код: Выделить всё

LRESULT CALLBACK WndProc (HWND jwnd, UINT msg, WPARAM wParam, LPARAM lParam)
При вызове DrawMenu(hwnd) компилятор не ругается, так как V-Studio выдает undeclared identifier только по одному разу (на каждый неверный ндентификатор переменной).
Можешь провести эксперимент. Закомментарь строку
SetMenu(hwnd,hMainMenu);
и получишь ругань на
DrawMenu(hwnd)

А WinMain тут вообще не причем, так как там hwnd объявлен локально, т.е. вне WinMain не виден.