17. programiranje za windows gui - marjan.fesb.hrmarjan.fesb.hr/~mateljan/cpp/pog17-programiranje za...
Post on 06-Feb-2018
237 Views
Preview:
TRANSCRIPT
Lekcija 17. Programiranje za Windows GUI 1
17. Programiranje za Windows GUI
17.1 Pristup programiranju Windows GUI programa pomoću
API "C" funkcija
17.1.1 "Hello World"
Da bi se na zaslonu dobio pozdrav iz naslova, u DOS okruženju bilo je dovoljno napisati
jednostavan program: void main() { printf("Hello World!"); }
Ekvivalent ovom programu na operacijskom sustavu Windows je sljedeći program:
#include <windows.h>
const char g_szClassName[] = "mojaKlasa";
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc; // karakteristike prozora
HWND hwnd; // identifikacija prozora
MSG Msg; // poruka
//Korak 1: Registriranje klase za kreiranje prozora
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Korak 2: kreiranje prozora
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"Primjer prozora",
WS_OVERLAPPEDWINDOW,
Lekcija 17. Programiranje za Windows GUI 2
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL) {
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Korak 3. Prokaz prozora
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Korak 4: Petlja koja procesira poruke
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
// Korak 5: funkcija koja obraduje poruke pristigle za prozor
LRESULT CALLBACK
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch(msg)
{
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
GetClientRect(hwnd,&rect);
DrawText(hdc,"Hello world!",-1,&rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd,&ps);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
Lekcija 17. Programiranje za Windows GUI 3
Slika 1 – Jednostavni prozor
Funkciju main() zamijenila je funkcija WinMain(), kojom započima svaki Windows
program. Grafičko sučelje Windows-a temelji se na grafičkom elementu – prozoru - po kojem
su i dobili ime. To je uokvirena pravokutna površina , koja se može pomicati na zaslonu i
kojoj se može mijenjati veličina. U zaglavlju prozora zapisan je naziv (naslov) prozora,
osnovni sistemski meni i gumbi za povećanje, minimiziranje i zatvaranje prozora. Ova
funkcionalnost je podržana od samog operacijskog ustava, i ne mora se posebno
implementirati u kodu (iako se može promijeniti predefinirana svojstva prozora).
17.1.2 Kreiranje prozora
Za kreiranje prozora koristi se funkcija CreateWindowEx, primjerice:
CreateWindowEx(WS_EX_CLIENTEDGE,g_szClassName,"Primjer
prozora",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,NULL,
NULL, hInstance, NULL);
stvata prozor imena "Primjer prozora".
Prvi argument ove funkcije je konstanta WS_EX_CLIENTEDGE koja definira izgled okvira
prozora, drugi je ime klase na kojoj se prozor temelji, a treći argument je string koji sadrži
tekst koji će biti ispisan u zaglavlju prozora kao njegov naslov. Konstanta
WS_OVERLAPPEDWINDOWS definira izgled i ponašanje prozora, a definirana je u
WINUSER.H datoteci. Sljedeća četiri parametra su koordinate ishodišta prozora X i Y te
širina i visina prozora. Parametri koji sljede su handle na prozor roditelj (handle je
cjelobrojna vrijednost koja jednoznačno definira aplikacijske komponente u operacijskom
sustavu), handle na meni, handle na instancu aplikacije, i pokazivač na podatke koji se
kreiraju prilikom stvaranja prozora.
Na početku funkcije WinMain(), deklarirana je varijabla wc tipa WNDCLASSEX
strukture. To je drugi argument pri pozivu funkcije CreateWindowEx(). WNDCLASSEX
struktura sadrži članove koji opisuju opće značajke prozora: veliku i malu ikonu, meni, boju
pozadine, stil prozora itd. ... Ta klasa, prije nego se upotrijebi za stvaranje prozora, mora se
registrirati u operacijskom sustavu, koristeći funkciju RegisterClassEx(). Tako registrirana
klasa poslije može biti upotrijebljena za stvaranje proizvoljnog broja prozora temeljenih na
njoj (tj. prozora s istim karakteristikama). Da bi, tako stvoreni prozor bio prikazan na zaslonu,
pozivaju se funkcije ShowWindow() i UpdateWindow().
U DOS konzolnom okruženju, kada je tipkovnica bila osnovni ulazni uređaj,
interakcija s korisnikom i unos podataka svodio se na testiranje pritisnute tipke na tipkovnici,
ili parsiranje unesenog stringa. U grafičkog okružju, gdje tekst nije glavni nositelj informacija,
Lekcija 17. Programiranje za Windows GUI 4
i kad se uz tipkovnicu pojavljuje i miš kao ravnopravan ulazni uređaj, način komunikacije na
relaciji korisnik – aplikacija – operacijski sustav se promijenio.
17.1.3 Windows procedure i poruke
Postavlja se pitanje kako prozor, nakon što je kreiran i prikazan na zaslonu, prima
korisnički unos bilo tipkovnicom bilo mišem. U Windowsima je taj problem riješen
sistemom poruka. Operacijski sustav prati sve aktivnosti ulaznih jedinica, te šalje
odgovarajuće poruke prozorima na koje se pojedini unos odnosi (klik mišem, prelazak
kursorom preko prozora, pritisak tipke na tipkovnici). Za svaki prozor Windowsi kreiraju red
poruka, iz kojeg petlja: while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
uzima jednu po jednu poruku i prosljeđuje je odgovarajućoj proceduri na daljnju obradu.
Funkcija GetMessage() uvijek vraća pozitivnu vrijednost 0 u slučaju kada je iz reda
dohvaćena poruka WM_QUIT , ili –1 u slučaju greške. WM_QUIT (WM- windows
message) signalizira izlazak iz programa ( klik na Close gumb, ili Alt+F4). U tom slučaju
while petlja se prekida, izlazi se iz WinMain() funkcije i program se prekida.
Treći član WNDCLASSEX strukture, deklariran kao lpfnWndproc (long pointer to
function), definira funkciju – windows proceduru - koja je zadužena za obradu svih pristiglih
poruka za prozore koji su kreirani na temelju te klase. Ta funkcija sadrži svu logiku aplikacije.
Realizacija windows procedure za prihvat događaja temelji se na switch-case strukturi, u kojoj
se u ovisnosti o vrsti poruke, događa neka akcija. Npr. ako želimo da se, kad korisnik klikne
na naš prozor, prikaže neka poruka, kodu s početka poglavlja u switch-case strukturi funkcije
WndProc treba dodati sljedeći kod: case WM_LBUTTONDOWN:
MessageBox(hwnd,"Prozor je kliknut" , "Poruka", MB_ICONINFORMATION);
break;
Ovo je jedan od najjednostavnijih primjera korisničke interakcije s aplikacijom i ne
odražava pravu složenost strukture Windows programa. I za relativno jednostavna korisnička
sučelja, ako se ne koriste posebne grafičke biblioteke, potrebno je detaljno poznavanje
funkcioniranja operacijskog sustava, načina slanja i obrade pristiglih poruka, brojnih API
funkcija i njihovih još brojnijih parametara. To u konačnici čini programiranje grafičkog
sučelja, putem direktnih Win32 API funkcijskih poziva, vrlo složenim zadatkom. Da bi se
doskočilo tom problemu razvijena su brojne biblioteka i razvojne okoline, MFC, Visual Basic
ili Borland Delphi, koje na više ili manje uspješan način enkapsuliraju složenost unutaranje
strukture Windows-a.
17.1.4 Kompajliranje i izvršenje programa
Kompajliranje programa se provodi pomoću IDE Visual Studio. Projekt se oformi na sljedeći
način:
Lekcija 17. Programiranje za Windows GUI 5
1) Komandom File->New->Project otvori se dijalog u kojeme se odabebre Project
Type: Win32 i Project->template : Win32 project. Odredi se staza foldera za
projekt i upiše ime projekta, primjerice "WinHello". Potvrdi se odabir s dugmetom
OK.
2) Otvori se novi dijalog u kojem se odabere dugme 'Next' i zatim se odabere
stavka 'Windows application' , postavi chek-box Empty project i klikne dugme
Finish.
3) U folder projekta kopiraje datoteku "WinHello.cpp" i dodajte projektu u
"Solution Explorer" na način da kliknete desni miš na ime projekta. To otvara meni
u kojem se komandom Add->Existing Item doda ova datoeka.
4) Kompajliranje se provodi komandom Project->Build
5) Kada je program kompajliran, može se izvršiti komandom Debug->Start
without Debugging.
17.2 Primjer izrade programa pomoću IDE Visual Studio i MFC
klasa
Upoznat ćemo se s MFC klasama i kako se pomoću njih piše GUI program. MFC
(Microsoft Foundation Classes) predstavlja skup klasa koje potpuno enkapsuliraju API
Win32. Većina današnjih profesionalnih programa je napisana pomoću ove bibilioteke.
17.2.1 Prvi program s MFC bibliotekom
Da bi napravili program pomoću MFC biblioteke potrebno je da se deklariraju barem
dvije klase: Jedna klasa koja predstavlja aplikaciju ( program) – nazovimo je sada
CMfcHelloApp i druga klasa koja predstavlja prozor (ili okvir) u kojem se ispisuje grafički
oblik programa – nazovimo je CmainFrame. Također ćemo upoznati klasu CDC pomoću koje
se vrše grafičke operacije (crtanje, bojanje i ispis teksta), te kako se deklariraju poruke
prozoru.
Korisničke klase su deklarirane u datoteci „MfcHello.h“:
#include <afxwin.h>
class CMainFrame : public CFrameWnd
{
public:
CMainFrame();
~CMainFrame();
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
};
class CMfcHelloApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
Lekcija 17. Programiranje za Windows GUI 6
CmainFrame nasljeđuje MFC klasu CframeWnd, CMfcHelloApp nasljeđuje MFC klasu
CwinApp.
Kod programa je u datoteci „MfcHello.cpp“
#include "MFCHello.h"
CMfcHelloApp MyApplication;
BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()
BOOL CMfcHelloApp::InitInstance()
{
CMainFrame* pFrame = new CMainFrame;
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMainFrame::CMainFrame()
{
Create(NULL,_T("MFC Skeleton"),
WS_OVERLAPPEDWINDOW,CRect(0,0,400,200),NULL);
}
CMainFrame::~CMainFrame()
{}
void CMainFrame::OnPaint()
{
CPaintDC dc(this);
dc.TextOut(100,50,"Hello World");
}
Kompajliranje programa se provodi pomoću IDE Visual Studio. Projekt se oformi na sljedeći
način:
1) Komandom File->New->Project otvori se dijalog u kojeme se odabebre Project
Type: Win32 i Project->template : Win32 project. Odredi se staza foldera za
projekt i upiše ime projekta, primjerice MfcHello. Potvrdi se odabir s dugmetom
OK.
2) Otvori se novi dijalog u kojem se odabere dugme Next i zatim se odabere
stavka 'Windows application' , postavi chek box Empty project i klikne dugme
Finish.
3) U folder projekta kopiraje datoteke "MfcHello.cpp" i "MfcHello.h" i dodajte
projektu u "Solution Explorer" na način da kliknete desni miš na ime projekta. To
otvara meni u kojem se komandom Add->Existing Item dodaju ove datoeke.
4) Još je potrebno u dijalogu konfiguracije, koji se otvori komandom Project-
>Properties->Configuration properties odabrat stavkui: Use of MFC -> Use MFC in
static Library
Lekcija 17. Programiranje za Windows GUI 7
5) Kompajliranje se provodi komandom Project->Build
6) Kada je program kompajliran, može se izvršiti komandom Debug->Start
without Debugging.
Dobije se prikaz:
U programu je najprije je deklarirana aplikacija MyApplication kao objekt klase
CMfcHelloApp.Zatim je u sekciji deklaracije poruka
BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()
označeno da će prozor primati poruku ON_WM_PAINT(). Kada se to ostvari automatski će
biti pozvana funkcija za crtanje: CMainFrame::OnPaint().
Pored ove poruke često se koriste sljedeće poruke: ON_WM_LBUTTONDOWN – klik na lijevi tipku miša
ON_WM_RBUTTONDOWN - klik na desnu tipku miša
ON_WM_MOUSEMOVE – poruka da je pomaknut miš
ON_WM_KEYDOWN – pritisnuta tipka na tipkovnici
ON_BN_CLICKED - pritisnuto dugme u grafičkom sučelje
ON_COMMAND – odabrana stavka menija
Moraju biti definirane i pripadne funkcije (to će biti objašnjeno kasnije)
U funkciji CMfcHelloApp::InitInstance() vrši se dinamičko stvaranje prozora:
CMainFrame* pFrame = new CMainFrame;
čiji se pokazivač pFrame sprema u aplikaciju, klao glavni prozor.
m_pMainWnd = pFrame;
Naredbe pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
prikazuju prozor i osvježavaju prikaz (zapravo se pošalje poruka WM_PAINT).
Crtanje grafičkog sadržaja vrši se u funkciji OnPaint(). U toj funkciji se za potrebe grafičkih
operacije otvara se objekt klase CPaintDC, i pomoću njega se ispisuje string "Hello World"
na koordinati prozora x=100, y=50.
Lekcija 17. Programiranje za Windows GUI 8
CPaintDC dc(this);
dc.TextOut(100,50,"Hello World");
CDC je temeljna klasa za grafički izlaz, a iz nje se definiraju izvedene klase: CWindowDC - Device context for the whole window
CPaintDC - Device context for the server area in Windows
CClientDC - Device context for the client area in Windows
CMetaFileDC - Device context for representing a Windows metafile for presenting pictures
Koordinatni sustav u Windows-ima je definiran tako da pixel u gornjem, lijevom kutu
predstavlja ishodite (x=0, y=0), a pixel u donjem, desnom kutu određuje maksimalnu
vrijednost x i y koordinate:
Svaki pixel je određen položajem i bojom. Za postavljanje boje (tip COLORREF), koristi se
makro RGB(r,g,b) - koji kombinira r- red, g-green, i b-blue indikatore, svaki u rasponu
od 0 do 255.
Primjerice: COLORREF crvena = RGB(255,0,0)
Odnos komponenti (crvene, zelene i plave boje) pri postavljanju proizvoljne boje.
U grafičkim operacijama intezivno se koriste klase:
Lekcija 17. Programiranje za Windows GUI 9
CPen – određuje boju i oblik pera za crtanje
CBrush – određuje oblik četke (šrafure i boje pozadine)
CFont – određuje font
CPoint – definira točku u 2D ravnini (članovi: x,y
CSize – definira veličinu u 2D ravnini (članovi: sx-širina, sy-visina)
CRect – definira pravokutnik u 2D ravnini (clanovi: x,y, width, height)
Funkcije koje su enkapsulirane u CDC klasi se često nazivaju GDI funkcijama (GDI –
graphical device interface). Često korištene funkcije su:
SelectObject(GDIobjekt) – GDIobjekt postaje aktivni objekt (pen, brush ili font)
Arc() – crta luk
Ellipse() – crta elipsi i kružnicu
Rectangle() – crta pravokutnik aktivnim perom i ispunjava ga aktivnom četkom
FillRect() - Fills a rectangular region with the indicated color
FillSolidRect() - Creates a rectangle using the specified fill color
GetPixel() - Gets the pixel value at the current position
SetPixel() - Draws a pixel according to the chosen color
LineTo() - Draws a line to the given coordinates
MoveTo() - Sets the current pen position to the indicated coordinates
Polyline() - Draws a series of lines passing through the given points
Za ispis teksta se koristi funkcije : SetBkColor() - Sets the background color of the text
SetTextColor() - Sets the color for the text
TextOut() - Displays a text message at the indicated coordinates
BitBlt() - Copies a bitmap to the current device context
Evo primjera primjene CDC operacija. U prethodnom program ćemo zamijeniti funkciju
OnPaint() sa sljedećom funkcijom:
void CMainFrame::OnPaint() { // Definiraj device context dc CPaintDC dc(this); // crtaj pravokutni okvir: //Najprije odredi tip četke za bojane unutarnje povrsine pravokutnika CBrush brushGray(RGB(192, 192, 192)); //Zatim postavi tu četku u dc i zapamti prethodnu četku
CBrush* brushOld = dc.SelectObject(&brushGray); //Zatim odredi tip pera za crtanje CPen penBlue(PS_SOLID,5,RGB(0,0,255)); //Zatim postavi to pero u device context dc CPen *oldPen = dc.SelectObject(&penBlue); //formiraj object klase CRect //(za definiranje koordineta pravokutnika koristi // objekte klase CPoint i CSize) CRect rc; rc=CRect(CPoint(10,30),CSize(300,200));
Lekcija 17. Programiranje za Windows GUI 10
// nacrtaj pravokutnik dc.Rectangle(rc); // Zatim ispiši text // definiraj boju pozadine i boju teksta dc.SetBkColor(RGB(192, 192, 192)); // gray background dc.SetTextColor(RGB(255,0,0)); // red text // ispiši tekst dc.TextOut(50,80, "Hello World"); // first message // i dodatni tekst zelene boje dc.SetTextColor(RGB(0,255,0)); // green text dc.TextOut(50,115, "MFC pomaze!"); // second message dc.SelectObject(brushOld); dc.SelectObject(oldPen); }
Dobije se prikaz:
17. 2.2 Glavne Klase u MFC biblioteci
Tipični windows program, pored definiranog glavnog prozora, ima mnoštvo definiranih
podprozora koji predstavljaju tzv. windows kontrole (menu bar, dijalog bar, status bar
dugmad, list box, edit box itd.) Za svaki od ovih prozora predviđena je posebna klase.
Najčešće koristene MFC klase su prikazane na sljedećoj slici.
Lekcija 17. Programiranje za Windows GUI 11
Hijerarhija “glavnih” MFC klasa
Često se koristi i klasa CString – za rad sa stringovima.
CFile se koristi za pristup datotekama.
U sljećem odjeljku će biti pokazano kako se pomoću IDE Visual Studio, tzv. vizuelnim
programiranjem kreira izgled i funkcionalnost tipičnog Windows programa. Također upoznat
ćemo programski oblik izgradnje softvera koji se naziva Dokument-View arhitektura.
Lekcija 17. Programiranje za Windows GUI 12
17.2.3 Document-View Arhitektura
MFC se temelji na tzv. Document-View programskoj arhitekturi.
CWinApp - aplikacijaCFrameWnd
CMenu
CStatusBar
CToolbar
CView
prikazuje dokument u
grafičkom obliku na
ekranu
CDocument
sadržava podatke
koje sprema na disk i/ili šalje u CView
Disk
Distributor poruka
za
Frame
View
Document
Cdialog, CDialogBar
CEdit ,CButton,
CListBox, CCombo
CStatic, itd.
Slika 2.
CWinApp je klasa kojom se generira aplikacija. Iz nje se kreiraju ostali objekti i vrši slanje
poruka.
CDocument klasa stvara objekte koji sadržavaju podatke koji se spremaju na disk (u tu svrhu
se koristi klasa CArchive) ili se u grafičkom obliku prikazuju u nekom prozoru.
CView klasa kontrolira grafički prozor koji je na raspolaganju korisniku (tzv. klijentu)
CFrameWnd je prozor oblika okvira koji sadrži objekte klase CView, te prozore za izbornik,
status bar, toolbar i dijalog bar.
CDialog klasa služi stvaranju dijaloga za unos podataka. Dijalozi sadrže različite
elemente, tzv. kontrole: CButton- botune, CListBox – liste, CCombo – kombo
liste, CEdit – prozore za unos teksta itd.
Lekcija 17. Programiranje za Windows GUI 13
17.2.3 Formiranje kostura MDI programa
Kreiranje programa se većim dijelom provodi vizulenim programiranjem pomoću IDE
Visual Studio. Omogućeno je generiranje i početnog kôda Windows programa. Pozivom
menija; New->Project dobije se dijalog u kojeg se unosi staza i ime projekta:
Uočite da je odabrana ikona koja pokazuje da će biti generiran program koji koristi
MFC klase.
Unesite:
Name: Fesb
Location: neka postojeća staza gdje spremate izvorni kod
Ako upišete c:\src Visual Studio će kreirati direktorij c:\src\Fesb, u kojeg će biti
upisane sve datoteke koje pripadaju projektu.
Nakon unosa, pritisnite botun OK. Tada ćete dobiti dijalog za postavljanje tipa
aplikacije:
Lekcija 17. Programiranje za Windows GUI 14
Četiri su temeljna tipa:
SDI - single document ( jedan dokument koji se prikazuje u jednom prozoru)
MDI – multiple document ( više dokumenta svaki sa svojim prozorom)
Multiple top level (a la Internet Explorer)
Dialog ( za jednostavne programe, koji ne obrađuju komplicirane podatke)
Odaberite drugu opciju, koja je tipična za većinu windows programa, i odaberite
standardnu MFC Document /View arhitekturu programa.
Nako pritiska botuna Finish, pojavljuje se treći dijalog u kojeg se unose podaci o sučelju
s korisnikom:
Lekcija 17. Programiranje za Windows GUI 15
Nakon pritiska botuna Finish: Visual Studio 7 generira 19 datoteka koje pridjeljuje
projektu. Pregled tih datoteka se dobije u "Solution" prozoru:
Korištene klase – hijerarhija
MFC klase -> ova aplikacija
CObject
CCmdTarget
CWinApp -> CFesbApp(u Fesb.Cpp)
CWnd
CFrameWnd
CChildFrame -> ChildFrm.cpp
CMDIFrameWnd -> MainFrm.Cpp
CWnd
CWiew ->CFesbView
CDocument ->CFesbDoc
CMDIDocument
CDialog
CAboutDlg ->Fesb.cpp
CControlBar
CToolBar -> MainFrm.Cpp
CStatusBar -> MainFrm.Cpp
Lekcija 17. Programiranje za Windows GUI 16
Kompilirajte program s komandom menija:
Project->Build Fesb
Zatim pozovite izvršenje programa komandom menija:
Project->Execute without Debug
Dobit ćete sljedeći izgled programa:
Dalje će biti pokazano:
kako korisnik u generirane datoteke umeće vlastiti kod.
kako podatke zapisuje u CDocument
kako grafički prikazuje sadržaj dokumenta u CView
kako povezuje komande – miša, tipkovnice, menija – s sistemom razmjene poruka
kako generira različite dijaloge
Najprije upoznajmo "glavni program", kako ga je generirao Visual studio
// Fesb.h : main header file for the Fesb application
#pragma once
#include "resource.h" // main symbols
// CFesbApp:See Fesb.cpp for the implementation of this class
class CFesbApp : public CWinApp
{
public:
CFesbApp();
// Overrides
public: virtual BOOL InitInstance();
// Implementation
afx_msg void OnAppAbout();
DECLARE_MESSAGE_MAP()
};
Lekcija 17. Programiranje za Windows GUI 17
extern CFesbApp theApp;
// Fesb.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "Fesb.h"
#include "MainFrm.h"
#include "ChildFrm.h"
#include "FesbDoc.h"
#include "FesbView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CFesbApp sustav razmjene poruka
BEGIN_MESSAGE_MAP(CFesbApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
// CFesbApp construction
CFesbApp::CFesbApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only CFesbApp object
CFesbApp theApp;
// CFesbApp initialization
BOOL CFesbApp::InitInstance()
{
// InitCommonControls() is required on Windows XP if an application
// manifest specifies use of ComCtl32.dll version 6 or later to
// enable visual styles. Otherwise, any window creation will fail.
InitCommonControls();
CWinApp::InitInstance();
// Initialize OLE libraries
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
}
AfxEnableControlContainer();
// Standard initialization
Lekcija 17. Programiranje za Windows GUI 18
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need
// Change the registry key under which our settings are stored
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
// Load standard INI file options (including MRU)
LoadStdProfileSettings(4);
// Register the application's document templates. Document
templates
// serve as the connection between documents, frames and views
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_FesbTYPE,
RUNTIME_CLASS(CFesbDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CFesbView));
AddDocTemplate(pDocTemplate);
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
// call DragAcceptFiles only if there's a suffix
// In an MDI app, this should occur immediately after
// setting m_pMainWnd
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line.
// Will return FALSE if
// app was launched with
// /RegServer, /Register, /Unregserver or /Unregister.
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The main window has been initialized, so show and update it
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX);
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
Lekcija 17. Programiranje za Windows GUI 19
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// App command to run the dialog
void CFesbApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
// CFesbApp message handlers
Najvažnija fukcija CFesbApp klasi je BOOL InitInstance() kojom se starta program.
U njoj je najvažniji dio:
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_FesbTYPE,
RUNTIME_CLASS(CFesbDoc),
1. RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CFesbView));
AddDocTemplate(pDocTemplate);
// create main MDI Frame window
2. CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
3. pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
Prvo se formira veza između dokumenta (CFesbDoc), i prozora u kojem će se grafički
prikazati njegov sadržaj (CChildFrame i CView).
Zatim se inicira glavni MDI prozor i konačno se prikazuje sve prozore koje sarži taj
glavni prozor.
Za sada, ne morate znati funkcionalnost ovog dijela programa.
MAIN FRAME je prozor koji osim prozora za prikaz dokumenata sadrži menije,
status bara i toolbar.
// MainFrm.h : interface of the CMainFrame class
//
#pragma once
class CMainFrame : public CMDIFrameWnd
{
DECLARE_DYNAMIC(CMainFrame)
public:
Lekcija 17. Programiranje za Windows GUI 20
CMainFrame();
// Attributes
public:
// Operations
public:
// Overrides
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected: // control bar embedded members
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
// Generated message map functions
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
DECLARE_MESSAGE_MAP()
};
Deklaracija CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
formira dva objekta koji predstavljaju status bar i toolbar. Oni se iniciraju u funkciji
CMainFrame::OnCreate
// MainFrm.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "Fesb.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
Lekcija 17. Programiranje za Windows GUI 21
ID_INDICATOR_SCRL,
};
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{ // TODO: add member initialization code here
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE
| CBRS_TOP| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY |
CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// Delete these 3 lines if you don't want the toolbar to be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CMDIFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return TRUE;
}
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{ CMDIFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{ CMDIFrameWnd::Dump(dc);
Lekcija 17. Programiranje za Windows GUI 22
}
#endif //_DEBUG
17.2.4 CHILD FRAME - je okvir za prikaz pojedinog dokumenta
// ChildFrm.h : interface of the CChildFrame class
//
#pragma once
class CChildFrame : public CMDIChildWnd
{
DECLARE_DYNCREATE(CChildFrame)
public:
CChildFrame();
// Attributes
public:
// Operations
public:
// Overrides
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// Implementation
public:
virtual ~CChildFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
};
// ChildFrm.cpp : implementation of the CChildFrame class
//
#include "stdafx.h"
#include "Fesb.h"
#include "ChildFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildFrame
IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWnd)
BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
END_MESSAGE_MAP()
Lekcija 17. Programiranje za Windows GUI 23
// CChildFrame construction/destruction
CChildFrame::CChildFrame()
{
// TODO: add member initialization code here
}
CChildFrame::~CChildFrame()
{
}
BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying the
CREATESTRUCT cs
if( !CMDIChildWnd::PreCreateWindow(cs) )
return FALSE;
return TRUE;
}
// CChildFrame diagnostics
#ifdef _DEBUG
void CChildFrame::AssertValid() const
{
CMDIChildWnd::AssertValid();
}
void CChildFrame::Dump(CDumpContext& dc) const
{
CMDIChildWnd::Dump(dc);
}
#endif //_DEBUG
// CChildFrame message handlers
17.2.5 Klasa CFesbDoc sadrži podatke dokumenta koji se obrađuje
Dodat ćemo podatke u string m_text:
1. CString m_text;
kojeg ćemo inicijalizirati u konstruktoru na vrijednost "Hello World", i klasu CPoint
2. CPoint m_pos;
koja sadrževa poziciju točke (u x,y koordinatana, koje iniciramo na 0,0)
// FesbDoc.h : interface of the CFesbDoc class
#pragma once
class CFesbDoc : public CDocument
{
protected: // create from serialization only
CFesbDoc();
Lekcija 17. Programiranje za Windows GUI 24
DECLARE_DYNCREATE(CFesbDoc)
// Attributes
public:
// Operations
public:
// Overrides
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
// Implementation
public:
virtual ~CFesbDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
// dodano
public:
CString m_text;
CPoint m_pos;
};
17.2.6 Klasa CView se koristi za ispis u klijentovom prozoru ChildFrm okvira
Dodajmo Klasi CView dva člana , za određivanje boje ispisa teksta i linija
COLORREF m_txtColor;
COLORREF m_penColor;
// FesbView.h : interface of the CFesbView class
//
#pragma once
class CFesbView : public CView
{
protected: // create from serialization only
CFesbView();
DECLARE_DYNCREATE(CFesbView)
// Attributes
public:
CFesbDoc* GetDocument() const;
Lekcija 17. Programiranje za Windows GUI 25
// Operations
public:
// Overrides
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
// Implementation
public:
virtual ~CFesbView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
// dodano
COLORREF m_txtColor;
COLORREF m_penColor;
};
#ifndef _DEBUG // debug version in FesbView.cpp
inline CFesbDoc* CFesbView::GetDocument() const
{ return reinterpret_cast<CFesbDoc*>(m_pDocument); }
#endif
Crtanje se vrši u predefiniranoj virtualnoj funkciji OnDraw(CDC *pDC) (pDC
je pokazivač na "device context – klasu" koja sadrži stanje grafičkog pogona – boju,
pen, rutine za ispis teksta, crtanje linija i poligona )
Mi ćemo dodati funkcionalnost kojom se u "iscrtava" tekst koji sadrži dokument i
ispisuje linija preko dijagonale klijentovog prozora. (Taj dio kôda je napisan "bold")
// FesbView.cpp : implementation of the CFesbView class
#include "stdafx.h"
#include "Fesb.h"
#include "FesbDoc.h"
#include "FesbView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CFesbView
IMPLEMENT_DYNCREATE(CFesbView, CView)
BEGIN_MESSAGE_MAP(CFesbView, CView)
Lekcija 17. Programiranje za Windows GUI 26
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
// CFesbView construction/destruction
CFesbView::CFesbView()
{ // TODO: add construction code here
m_txtColor = RGB(0,0,0); // crna
m_penColor = RGB(128,0,0); // crvena
}
CFesbView::~CFesbView()
{}
// CFesbView drawing
void CFesbView::OnDraw(CDC* pDC)
{
CFesbDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//ispisi text
pDC->SetTextColor(m_txtColor);
pDC->TextOut(pDoc->m_pos.x,pDoc->m_pos.y,pDoc->m_text);
//nacrtaj liniju dijagonalno preko cijelog prikaza
CRect r;
GetClientRect(&r);
CPen pen;
pen.CreatePen(PS_SOLID,1,m_penColor);
CPen *oldpen= pDC->SelectObject(&pen);
pDC->MoveTo(r.left,r.bottom);
pDC->LineTo(r.right,r.top);
pDC->SelectObject(oldpen); // vrati staro stanje
}
BOOL CFesbView::PreCreateWindow(CREATESTRUCT& cs)
{ // TODO: Modify the Window class by modifying the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
// CFesbView printing
BOOL CFesbView::OnPreparePrinting(CPrintInfo* pInfo)
{ // default preparation
return DoPreparePrinting(pInfo);
}
void CFesbView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{ // TODO: add extra initialization before printing
}
void CFesbView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{ // TODO: add cleanup after printing
}
// CFesbView diagnostics
Lekcija 17. Programiranje za Windows GUI 27
#ifdef _DEBUG
void CFesbView::AssertValid() const
{ CView::AssertValid();
}
void CFesbView::Dump(CDumpContext& dc) const
{ CView::Dump(dc);
}
CFesbDoc* CFesbView::GetDocument() const // non-debug version is
inline
{ ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFesbDoc)));
return (CFesbDoc*)m_pDocument;
}
#endif //_DEBUG
Interesira nas kako se vrši korisnička interakcija pomoću miša, tipkovnice, menija i
dijaloga .
17.2.7. Interakcija pomoću miša i tipkovnice
Za svaku interaktivnu klasu, u ovom
slučaju CView:
"Properties prozor" – omogućuju
generiranje koda za prihvat poruka
Lijevo je popis standardnih poruka,
kojima se može pridijeliti funkcija (desno)
koja će se izvršiti kada prozor primi tu
poruku.
Mi ćemo obraditi poruke
WM_KEYDOWN – pritisnuta tipka
WM_LBUTTONDOWN – pritisnut
lijevi botun na mišu
za koje e generiraju funkcije:
OnKeyDown() – pritisnuta tipka
OnLButtonDown() – pritisnut lijevi
botun miša
Generirane su dvije funkciju u CView:
void CFesbView::OnLButtonDown(UINT nFlags, CPoint point)
{ // TODO: Add your message handler code here and/or call default
Lekcija 17. Programiranje za Windows GUI 28
CView::OnLButtonDown(nFlags, point);
}
void CFesbView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{ // TODO: Add your message handler code here and/or call default
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
Zadatak: napisati program koji će reagirati na ova dva događaja:
1. Pritisnut lijevi botun miša Akcija: koordinate miša zapiši u koordinate ispisa teksta i
obnovi prikaz na ekranu
2. Pritisak kursorskih tipki (strelica) - koje imaju "defines": VK_UP, VK_DOWN, VK_RIGHT, VK_LEFT
Akcija: pomakni ispis teksta za jedno mjesto u smjeru strelice
void CFesbView::OnLButtonDown(UINT nFlags, CPoint point)
{
CFesbDoc* pDoc = GetDocument();
pDoc->m_pos = point; // point sadrži koordinate miša
Invalidate(); // poruka da se treba obnoviti crtanje View-a
CView::OnLButtonDown(nFlags, point);
}
void CFesbView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CFesbDoc* pDoc = GetDocument();
CPoint curr_pos = pDoc->m_pos;
switch(nChar)
{
case VK_UP: curr_pos.y--; break;
case VK_DOWN: curr_pos.y++;break;
case VK_LEFT: curr_pos.x--; break;
case VK_RIGHT: curr_pos.x++;break;
}
// osiguraj se da je ispis u klijentovom prozoru
CRect r;
GetClientRect(&r);
if(curr_pos.y > r.top && curr_pos.y < r.bottom)
pDoc->m_pos.y = curr_pos.y;
if(curr_pos.x > r.left && curr_pos.x < r.right)
pDoc->m_pos.x = curr_pos.x;
Invalidate(); // poruka da se treba obnoviti crtanje View-a
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
Ponovo kompilirajte program i provjerite da li se izvršava prema predviđenim akcijama.
Uočite da je Visual studio u FesbView.h generirao dvije deklaracije
Lekcija 17. Programiranje za Windows GUI 29
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
Prefiks afx_msg je oznaka kompilatoru da se ova funkcija koristi kao "event handler"
Implementacija ovih funkcija, i njihova veza s "događajima" (event handler) je u
datoteci FesbView.cpp, kako slijedi:
BEGIN_MESSAGE_MAP(CFesbView, CView)
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
ON_WM_LBUTTONDOWN()
ON_WM_KEYDOWN()
END_MESSAGE_MAP()
čime se omogućuje razmjena poruka s tipkovnicom i mišom.
17.2.8 Interakcija pomoću menija
Menije se kreira pomoću "resource editora", sljedećim postupkom:
Postavite se u resource editor i kliknite na "meni"- IDR_FesbTYPE. Dobit će te prikaz
menija:
U kockicu "Type here" otkucajte
&Novi tekst
Zatim kliknite na Properties box i
zapišite identifikaciju ovog menija kao
ID_EDIT_NOVITEXT
Lekcija 17. Programiranje za Windows GUI 30
U rubrici prompt se zapisuje tekst koji
se ispisuje u na status baru, kada se selektira
ovaj meni.
Ponovo kompjlirajte program, i izvršite ga. Primjetit ćete da se pojavio ovaj meni, ali u
neaktivnom stanju.
Da bi ovi meniji postali aktivni mora se svakom meniju pridijeliti poruka i funkcija koja
se izvršava kada se primi komanda iz menija. tj. mora se definirati "event handler"
Event handler funkcija za komande
menija se automatski formira tako da se
klikne desnim mišom na stavku menija – tada
se otvori izbornik u kojem treba odabrati
stavku
Add Event handler
kada se to izvrši dobije se sljedeći
dijalog
Lekcija 17. Programiranje za Windows GUI 31
Odaberite klasu CFesbView i kliknite Add and Edit.
Visual studio tada automatski generira funkciju
void CFesbView::OnEditNovitext()
{
// TODO: Add your command handler code here
}
čiju deklaraciju zapisuje u obliku
afx_msg void OnEditNovitext();
Također je generiran kod
BEGIN_MESSAGE_MAP(CFesbView, CView)
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
ON_WM_LBUTTONDOWN()
ON_WM_KEYDOWN()
ON_COMMAND(ID_EDIT_NOVITEXT, OnEditNovitext)
END_MESSAGE_MAP()
čime je uspostavljen event handler.
U funkciju sada upišite:
void CFesbView::OnEditNovitext()
{
// TODO: Add your command handler code here
Lekcija 17. Programiranje za Windows GUI 32
AfxMessageBox("Pritisnut je meni: NOVI text")
}
Kompilirajte program i izvršite ga. Aktivirajte meni Edit->Novi text
i na ekranu će biti prikaz:
dakle, funkcija AfxMessageBox(char *str), je jednostavni način da se ispiše poruka
korisniku.
17.2.9 Interakcija pomoću dijaloga
Najprije formirajmo predložak za dijalog. Postavite se u resource editor i izvršite desni
klik na Dialog-Insert new dialog. Dobit će te dialog
njemu je prodjeljen identifikator IDD_DIALOG1. Otvorite properies i promijenite ovaj
identifikator u IDD_DIALOG1_TEXT. Ako želite promijenite i ime dijaloga u stavci
"Caption".
Lekcija 17. Programiranje za Windows GUI 33
Ovaj dijalog se povezuje s programom tako da se za njega formira posebna klasa tipa
CDialog.
Kliknite desnim botunom miša u području dijaloga. Pojavit će se sljedeći meni:
Odaberite
Add Class
Lekcija 17. Programiranje za Windows GUI 34
i Visula Studio vam nudi dijalog:
Ispunite ga kako je prikazano, kliknite "Finish" i Visual Studio generira klasu CTxtDlg.
#pragma once
#include "afxwin.h"
// CTxtDlg dialog
class CTxtDlg : public CDialog
{
DECLARE_DYNAMIC(CTxtDlg)
public:
CTxtDlg(CWnd* pParent = NULL); // standard constructor
virtual ~CTxtDlg();
// Dialog Data
enum { IDD = IDD_DIALOG_TEXT };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV
support
DECLARE_MESSAGE_MAP()
};
// TxtDlg.cpp : implementation file
Lekcija 17. Programiranje za Windows GUI 35
//
#include "stdafx.h"
#include "Fesb.h"
#include "TxtDlg.h"
// CTxtDlg dialog
IMPLEMENT_DYNAMIC(CTxtDlg, CDialog)
CTxtDlg::CTxtDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTxtDlg::IDD, pParent)
{
}
CTxtDlg::~CTxtDlg()
{
}
void CTxtDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CTxtDlg, CDialog)
END_MESSAGE_MAP()
Lekcija 17. Programiranje za Windows GUI 36
Sada ćemo u ovaj dijalog dodati dvije "kontrole"
Static - za poruku korisniku
Edit – za unos teksta
Zatim ćemo dodati varijablu u dijalog box – tipa CEdit, koja ce poslužiti za prihvat
unesenog teksta; Da bi to napravili, na dijalog boxu, u području Edit kontrole pritisnite desni
botun miša... i odaberite -- Add variable
Lekcija 17. Programiranje za Windows GUI 37
Pojavljuje se sljedeći dijalog
Unesite ime varijable m_txtEdit i kliknite botun Finish.
Visual Studio u prethodni kod CTxtDlg klase generira varijablu tipa CEdit i imena
m_txtEdit. Mi ćemo dodati još jednu varijablu CString m_text;
Ta varijabla će sadržavati tekst koji unese korisnik, a dobavit ćemo ga pozivom
m_txtEdit.GetWindowText(m_text)
kada korisnik otkuca OK.
Lekcija 17. Programiranje za Windows GUI 38
Da bi to omogućili moramo instalirati event handler za tipku OK. To se postiže tako da
se
u Properties odabere ikona
i izvrši izbor predefinirane virtuele funkcije OnOk()
Nakon toga Visual Studio generira funkciju:
void CTxtDlg::OnOK()
{
// TODO: Add your specialized code here and/or call the base class
CDialog::OnOK();
}
u koji treba upisati kod:
void CTxtDlg::OnOK()
{
m_txtEdit.GetWindowText(m_text) ;
CDialog::OnOK();
}
Lekcija 17. Programiranje za Windows GUI 39
Zapamtite : Poruke se šalju pomoću event handlera preko poruka ili tako da se
preoptereti event handler iz predefiniranih klasa.
Da bi mogli koristiti ovaj dijalog treba još pokazati:
- kako se poziva dijalog box
- kako se dobavlja informacija iz dijalog boxa u glavni program.
Iniciranje dijalog boxa može biti prečicom (tipkovnicom) ili preko poruka koje se
distribuiraju putem menija.
Evo načina da se dijalog pozove preko menija. Iskoristit ćemo prije definirani meni:
Novi text i u njegov "event handler" upisati kod:
void CFesbView::OnEditNovitext()
{
CFesbDoc* pDoc = GetDocument();
CTxtDlg dlg; // deklariranje dijaloga
int response = dlg.DoModal(); //poziv dijaloga
if(IDOK == response) // samo ako je pritisnut botun OK
{
CString s;
// dobavi txt iz dijaloga
if(dlg.m_text.IsEmpty()) // ako je prazan
AfxMessageBox("Unijeli ste prazan tekst");
else
pDoc->m_text = dlg.m_text; // stavi tekst u dokument
Invalidate();
}
}
Također, u datoteku FesbView.cpp treba dodati:
#include "stdafx.h"
#include "Fesb.h"
#include "FesbDoc.h"
#include "FesbView.h"
#include "TxtDlg.h"
Sada Kompilirajte program i probajte funkcionalnost dijaloga. Vidjet će te da je ovo
jedan tipični Windows program, kojem još jedino nedostaje mogućnost da se podaci spreme
na disk.
Također, potrebno je pokazati kako se vrši interakcija pomoću toolbara.
Lekcija 17. Programiranje za Windows GUI 40
17.2.10 Interakcija pomoću toolbara
Pokazat ćemo kako se na toolbar dodaje ikona kojoj će biti namjena de se njome
aktivira komanda menija:Novi text.
U resource prozoru aktivirajte toolbar IDF_MAINFRAME. Kliknite na posljednju
praznu ikonu.
Nacrtajte u ovoj ikoni slovo T
i kliknite desnim btunom miša
Pokrenite meni Properties, i u stavku ID
otkucajte identifikator Novi text menija,
tj. ID_EDIT_NOVITEXT
Kompilirajte i pokrenite program.
Vidjet ćete da se sada može pozvati dijalog za unos teksta pritiskom na ovi ikonu.
Lekcija 17. Programiranje za Windows GUI 41
17.2.11 Spremanje i čitanje dokumenta
Naš dokument sadrži samo dva podatka string m_text i poziciju m_pos:
Pored ova dva podatka na početak datoteke ćemo zapisati 4 znaka: "FESB" koji će
služiti identifikaciji datoteke.
MFC klase potpuno enkapsuliraju rad s binarnim datotekama. Jedino što korisnik mora
napraviti je ispuniti funkciju Serialize(CArchive& ar) koja je definirana u FesbDoc.cpp;
void CFesbDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring()) {
// TODO: add storing code here
}
else {
// TODO: add loading code here
}
}
Klasa CArchive omogućuje pristup datoteci pomoću operatora >> i << s logikom kao
kod standardnih klasa, ali se zapis ne vrši formatirano već u binarnom obliku. U našem
slučaju kod izgleda ovako:
void CFesbDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring()) // spremanje u datoteku
{
ar << 'F'<< 'E'<< 'S'<< 'B';
ar << m_pos;
ar << m_text;
}
else // citanje iz datoteke
{
char c1,c2,c3,c4;
ar >> c1 >> c2 >> c3 >> c4;
if(c1 != 'F' || c2 != 'E' || c3 != 'S' || c4 != 'B')
{
AfxMessageBox("Ovo nije fesb datoteka"); return;
}
// ok, citaj poziciju i string
ar >> m_pos;
ar >> m_text;
}
}
Probajte sada izvršiti ovaj kompletni Windows program.
Primjetit ćete da je potpuno podržan pristup datotekama: izbor direktorija, otvaranje i
zatvaranje datoteka, pamćenje prethodno otvorenih datoteka - sve je enkapsulirano unutar
MFC klasa i funkcija.
top related