NWP
NWP
NWP
programiranje
Nenad Čaklović
nenad.caklovic@vsite.hr
NWP
1. predavanje
• WinMain
• klase prozora
• procedura prozora
• poruke, petlja poruka
WinMain
#include <windows.h>
// wtypes.h
typedef char CHAR;
typedef CHAR* PSTR;
typedef const CHAR* PCSTR;
#ifdef STRICT
#define DECLARE_HANDLE(name) struct name##__ { int unused; };
#else
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
DECLARE_HANDLE(HINSTANCE);
DECLARE_HANDLE(HICON);
DECLARE_HANDLE(HCURSOR);
DECLARE_HANDLE(HBRUSH);
DECLARE_HANDLE(HWND);
WNDCLASS
typedef struct
{
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
PCTSTR lpszMenuName;
PCTSTR lpszClassName;
}
WNDCLASS;
HWND CreateWindow(
PCTSTR lpClassName,
PCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
PVOID lpParam
);
// windef.h
#define CALLBACK __stdcall
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
typedef struct
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}
MSG;
BOOL PostMessage(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
• resursi
Resursi (resources)
vrste:
• ikona (icon)
• kursor (cursor)
• tekst (string)
• prečica (accelerator)
• novi (custom)
• meni (menu)
• dijalog (dialog box)
• slika (bitmap)
Datoteka sa resursima
• sadržaj datoteke:
// app.rc
#include "resource.h"
IDI_MAIN ICON "ikona.ico"
// resource.h
#define IDI_MAIN 101
#include "resource.h"
HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN));
• učitavanje:
STRINGTABLE
BEGIN
IDS_STRING1 "prvi tekst"
IDS_STRING2 "drugi tekst"
...
END
• tekst može sadržavati \t i \n, maksimalna duljina je 4097 znakova
char s[128];
LoadString(hInstance, IDS_STRING1, s, sizeof s);
Prečica
ID_ACCEL ACCELERATORS
BEGIN
"N", ID_FILE_NEW, VIRTKEY, CONTROL
VK_INSERT, ID_EDIT_PASTE, VIRTKEY, SHIFT
VK_F1, ID_SOMETHING, VIRTKEY, CONTROL, ALT
...
END
• učitavanje i korištenje:
• učitavanje i korištenje:
IDM_MAIN MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New", ID_FILE_NEW
MENUITEM SEPARATOR
MENUITEM "E&xit", ID_FILE_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&Index", ID_HELP_INDEX, GRAYED
MENUITEM "&Tooltips", ID_HELP_TIPS, CHECKED
MENUITEM "&About", ID_HELP_ABOUT
END
END
Meni
• učitavanje
• pridjeljivanje prozoru:
kao parametar u CreateWindow ili
SetMenu(hWnd, hMenu);
...
case WM_CONTEXTMENU:
HMENU hPopup = GetSubMenu(GetMenu(hwnd), 0); // ili Create
DWORD pos = GetMessagePos();
int x = GET_X_LPARAM(pos), y = GET_Y_LPARAM(pos);
UINT id = TrackPopupMenu(hPopup, TPM_RETURNCMD,
x, y, 0, hwnd, 0);
return 0;
...
3. predavanje
• dijalozi
– modalni
– nemodalni
– standardni
Dijalog
• koordinate:
po x-u 1/4 prosječne širine znaka
po y-u 1/8 prosječne visine znaka
• koriste se kad korisnik mora moći obaviti i neku drugu operaciju dok je dijalog
prikazan (primjer: "Find/Replace" dijalog)
• aktiviranje dijaloga:
HWND CreateDialog(HINSTANCE hInstance, LPCTSTR template,
HWND parent, DLGPROC dlgProc);
DestroyWindow(hDlg);
Promjene u petlji poruka
• poruke za nemodalne dijaloge idu kroz petlju poruka, zato se petlja poruka mora
promijeniti
LOGFONT lf = {0};
strcpy(lf.lfFaceName, "Arial");
CHOOSEFONT cf;
ZeroMemory(&cf, sizeof cf);
cf.lStructSize = sizeof cf;
cf.Flags = CF_INITTOLOGFONTSTRUCT
| CF_SCREENFONTS | CF_EFFECTS;
cf.lpLogFont = &lf;
if(ChooseFont(&cf))
CreateFontIndirect(&lf);
Dijalog za otvaranje/spremanje datoteke
ofn.Flags = OFN_HIDEREADONLY;
if(GetOpenFileName(&ofn))
// otvori "path"
ofn.Flags = OFN_HIDEREADONLY |
OFN_OVERWRITEPROMPT;
if(GetSaveFileName(&ofn))
// spremi u "path"
4. predavanje
• subclassing
• Unicode
Parametri klase
WNDPROC origWndProc;
// subclass hwnd
origWndProc = (WNDPROC)SetWindowLong(hwnd,GWL_WNDPROC,(LONG)AlterWndProc);
LRESULT CALLBACK AlterWndProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp)
{
if(msg == WM_KEYDOWN)
// something
return CallWindowProc(origWndProc, hw, msg, wp, lp) ;
}
• preteče današnjih setova: Braille oko 1820, Morse oko 1850, telex kodovi
• 1967. 7-bitni ASCII standard (26 malih slova, 26 velikih slova, 10 brojki, 32
simbola, 33 kontrol-koda i razmak = 128)
• 1981. 8-bitni standard za IBM PC - popunjeno još 128 znakova
• 1987 (MS DOS 3.3) uvodi kodne stranice, koncept preuzimaju i Windowsi -
gornjih 128 znakova se mapiraju preko tablice
char c = 'M';
char* s = "VEST";
char a[] = "NWP";
• standardne funkcije:
strlen wcslen
strcpy wcscpy
strcat wcscat
...
TCHAR
TCHAR c = _T('M');
TCHAR* s = _T("VEST");
TCHAR a[] = _T("NWP");
Setovi znakova u Windowsima
// winuser.h
#ifdef _UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif
Tipkovnica
// funkcije // poruke
HWND GetFocus(); WM_SETFOCUS // prozor dobiva fokus
HWND SetFocus(HWND); WM_KILLFOCUS // prozor gubi fokus
• poruke sa tipkovnice i miša prvo idu u posebni red poruka - system message queue
• GetKeyState() - da li je tipka pritisnuta, obično se koristi za Ctrl, Shift
// poruke
WM_KEYDOWN
• u WPARAM virtualni kod tipke
WM_KEYUP
// funkcije
GetSystemMetrics(SM_MOUSEPRESENT); • da li je miš prisutan
POINT p; GetCursorPos(&p);
• pozicija kursora na ekranu
SetCursorPos(x, y);
// poruke
WM_LBUTTONDOWN WM_RBUTTONDOWN WM_MBUTTONDOWN
WM_LBUTTONUP WM_RBUTTONUP WM_MBUTTONUP
WM_LBUTTONDBLCLK WM_RBUTTONDBLCLK WM_MBUTTONDBLCLK
WM_MOUSEMOVE
WM_MOUSEWHEEL
x = GET_X_LPARAM(lParam);
y = GET_Y_LPARAM(lParam);
// funkcije
SetTimer(hwnd, idTimer, milisec, timerProc);
KillTimer(hwnd, idTimer);
• GDI - osnove
Dijelovi prozora
title bar
menu bar
0, 0
klijentsko
područje
status bar
// funkcije
GetClientRect(hwnd, &rect);
GetWindowRect(hwnd, &rect); // koordinate na ekranu
// poruke
WM_SIZE • u LPARAM nova veličina klijentskog područja
WM_GETMINMAXINFO • za postavljanje ograničenja (min, max veličina prozora)
Crtanje po prozoru
// poruka
WM_PAINT
• nevažeće područje (invalid region, update region) - onaj dio koji se mora
ponovno iscrtati
• ako se pojavi novo nevažeće područje dok poruka još nije obrađena, Windowsi
izračunaju novi nevažeći pravokutnik (ne šalje se nova poruka)
// funkcije
GetUpdateRect • vraća nevažeći pravokutnik
// WindowProc
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// GDI funkcije
EndPaint(hwnd, &ps);
return 0;
GetDeviceCaps(hdc, index);
• mogućnosti DC-a:
– rezolucija (HORZRES, VERTRES)
– broj boja (BITSPIXEL, PLANES)
– broj piksela po inchu (LOGPIXELSX, LOGPIXELSY)
– mogućnosti pri ispisu teksta (TEXTCAPS), crtanju linija (LINECAPS), crtanju krivulja
(CURVECAPS), crtanju bitmapa(RASTERCAPS), ...
GetSystemMetrics(index);
// SM_CXFRAME, SM_CYCAPTION, SM_CYMENU, SM_NETWORK, ...
SystemParametersInfo(index, ...)
// SPI_GETSCREENSAVEACTIVE, SPI_GETDRAGFULLWINDOWS,
SPI_GETNONCLIENTMETRICS, SPI_GETDESKWALLPAPER, ...
Device context bez WM_PAINT
int id = SaveDC(hdc);
// funkcije za promjenu svojstava
RestoreDC(hdc, id);
SaveDC(hdc);
// funkcije za promjenu svojstava
RestoreDC(hdc, -1);
WNDCLASS wc;
wc.style = CS_OWNDC;
SelectObject
• GDI
Piksel
// funkcije
COLORREF GetPixel(hdc, x, y);
SetPixel(hdc, x, y, color);
LineTo(hdc, x, y);
Polyline(hdc, arrPts, count);
PolyPolyline(hdc, arrPts, arrCnt, numPol);
PolyBezier(hdc, arrPts, count);
• primjeri:
POINT p[] = { 20, 20, 50, 20, 50, 50, 20, 50, 20, 20 };
Polyline(hdc, p, sizeof(p)/sizeof(p[0]));
Olovka (pen)
• style:
DeleteObject(HGDIOBJ);
SelectObject (2)
• isto, ali kraće (koristi što SelectObject uvijek vraća prethodno selektirani)
• primjeri:
POINT p[] = { 20, 20, 50, 20, 50, 50, 20, 50, 20, 20 };
Polygon(hdc, p, sizeof(p)/sizeof(p[0]));
Četka (brush)
HBRUSH CreateSolidBrush(color);
HBRUSH CreateHatchBrush(style, color);
• style:
SetPolyFillMode(hdc, mode);
• mode:
ALTERNATE WINDING
Tekst
• dodatne funkcije:
SetTextAlign(hdc, mode); • poravnanje (TA_LEFT, TA_TOP, ...)
SetTextColor(hdc, col);
SetBkColor(hdc, col);
SetBkMode(hdc, mode); • pozadina (OPAQUE, TRANSPARENT)
• primjeri:
std::basic_string<TCHAR> s = _T("NWP");
TextOut(hdc, 100, 100, s.c_str(), s.length());
• parametri:
– height: pozitivna = ukupna visina reda,
negativna = -pointSize*GetDeviceCaps(hdc, LOGPIXELSY)/72
– escapement: nagib u desetinama stupnja
– weight: FW_NORMAL, FW_BOLD
– italic, underline, strikeout: TRUE/FALSE
– charset: ANSI_CHARSET, EASTEUROPE_CHARSET, GREEK_CHARSET, ...
– pitch_family: FIXED_PITCH/VARIABLE_PITCH, FF_ROMAN, FF_SWISS, ...
– name: "Arial", "Times New Roman", ...
Regije
SelectObject(hdc, hrgn);
SelectClipRgn(hdc, hrgn);
Način crtanja (drawing mode)
// funkcija
P: 1 1 0 0
SetROP2(hdc, mode); mode:
D: 1 0 1 0
R2_BLACK 0 0 0 0 0
R2_NOTMERGEPEN 0 0 0 1 ~(P ¦ D)
• ROP2 - binarna raster operacija
R2_MASKNOTPEN 0 0 1 0 ~P & D
– P (pen)
R2_NOTCOPYPEN 0 0 1 1 ~P
– D (destination)
R2_MASKPENNOT 0 1 0 0 P & ~D
R2_NOT 0 1 0 1 ~D
R2_XORPEN 0 1 1 0 P ^ D
R2_NOTMASKPEN 0 1 1 1 ~(P & D)
R2_MASKPEN 1 0 0 0 P & D
R2_NOTXORPEN 1 0 0 1 ~(P ^ D)
R2_NOP 1 0 1 0 D
R2_MERGENOTPEN 1 0 1 1 ~P ¦ D
R2_COPYPEN 1 1 0 0 P
R2_MERGEPENNOT 1 1 0 1 P ¦ ~D
R2_MERGEPEN 1 1 1 0 P ¦ D
R2_WHITE 1 1 1 1 1
Način mapiranja (mapping mode)
xViewExt
xViewport (xWindow - xWinOrg) * xViewOrg
xWinExt
• načini mapiranja:
– jedinica piksel, y raste prema dole - MM_TEXT
– jedinica proizvoljna, y raste prema gore - MM_LOMETRIC (0.1 mm), MM_HIMETRIC (0.01
mm), MM_LOENGLISH (0.01 inch), MM_HIENGLISH (0.001 inch), MM_TWIPS (1/1440
inch)
– sve proizvoljno - MM_ISOTROPIC (x = y), MM_ANISOTROPIC (x != y)
// funkcija
SetMapMode(hdc, mode);
Način mapiranja - primjer
• MFC - uvod
Povijest
• metode:
• metode:
CWnd* GetParent();
CWnd* GetDlgItem(int id) const;
BOOL ModifyStyle(DWORD remove, DWORD add, UINT flags);
void CenterWindow(CWnd* altParent = NULL);
• članovi:
public:
HINSTANCE m_hInstance; // ili AfxGetInstanceHandle();
LPTSTR m_lpCmdLine;
LPCTSTR m_pszAppName; // ili AfxGetAppName();
// iz resursa (AFX_IDS_APP_TITLE)
...
• virtualne metode:
BOOL InitInstance();
int ExitInstance();
int Run();
BOOL OnIdle(LONG count);
...
• uvijek postoji (jedan) globalni objekt klase izvedene iz CWinApp
• globalna funkcija za dohvat (izvedenog) CWinApp objekta
CWinApp* AfxGetApp();
Minimalni program
#include <afxwin.h>
MyApp theApp;
Poruke
• prozor koji želi primati poruke mora imati mapu poruka
// u .cpp
BEGIN_MESSAGE_MAP(klasa, bazna_klasa)
// poruke
END_MESSAGE_MAP()
• u mapi poruka:
ON_WM_xxx
ON_COMMAND(id, funkcija)
BEGIN_MESSAGE_MAP(MainWindow, CFrameWnd)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
• MFC
– dijalozi
– kontrole
CDialog
• bazna klasa za sve dijaloge (modalne i nemodalne)
• modalni:
– konstruktor sa resursnim ID (LPCTSTR ili UINT)
– kreiranje prozora - DoModal()
– zatvaranje - EndDialog()
• nemodalni:
– prazni konstruktor
– kreiranje prozora - Create() sa resursnim ID (LPCTSTR ili UINT)
– zatvaranje - DestroyWindow()
primjer modalnog dijaloga
• primjeri:
BEGIN_MESSAGE_MAP(SomeDialog, CDialog)
ON_CONTROL(BN_CLICKED, IDC_BUTTON1, OnButtonClicked)
ON_CONTROL(EN_CHANGE, IDC_EDIT1, OnEditChanged)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(SomeDialog, CDialog)
ON_BN_CLICKED(IDC_BUTTON1, OnButtonClicked)
ON_EN_CHANGE(IDC_EDIT1, OnEditChanged)
END_MESSAGE_MAP()
BOOL SomeDialog::OnInitDialog(){
CDialog::OnInitDialog();
CEdit* pEdit = static_cast<CEdit*>(GetDlgItem(IDC_EDIT1));
pEdit->SetWindowText(_T("abc"));
CListBox* pListBox=static_cast<CListBox*>(GetDlgItem(IDC_LIST1));
pListBox->AddString(_T("prvi"));
pListBox->AddString(_T("drugi"));
return TRUE;
}
void SomeDialog::OnOK() {
CEdit* pEdit = static_cast<CEdit*>(GetDlgItem(IDC_EDIT1));
CString s; pEdit->GetWindowText(s);
CListBox* pListBox=static_cast<CListBox*>(GetDlgItem(IDC_LIST1));
int selected = pListBox->GetCurSel();
CDialog::OnOK();
}
DDX
BOOL SomeDialog::OnInitDialog(){
CDialog::OnInitDialog();
edit.SetWindowText(_T("abc"));
return TRUE;
}
void SomeDialog::OnOK() {
CString s; edit.GetWindowText(s);
CDialog::OnOK();
}
};
DDX - vrijednosti
void SomeWnd::ShowDialog(){
SimpleDialog dlg(this);
dlg.text = _T("abc");
if(dlg.DoModal() == IDOK)
MessageBox(dlg.text);
}
DDV
void SomeWnd::ShowDialog(){
SimpleDialog dlg(this);
dlg.n = 15;
dlg.d = -1.25;
dlg.DoModal();
}
"nove" kontrole (common controls)
BEGIN_MESSAGE_MAP(SomeDialog, CDialog)
ON_NOTIFY(NM_CLICK, IDC_LIST1, OnListClick)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, OnListItemChanged)
END_MESSAGE_MAP()
• dokument/pogled
• MDI
dokument/pogled
• razdvajanje sadržaja (podataka) od prikaza
CDocument CView
CDocument
• komunikacija prema svim pogledima
void UpdateAllViews(CView* sender,LPARAM msg=0,CObject* param=0);
• virtualne funkcije
BOOL OnNewDocument();
BOOL OnOpenDocument(LPCTSTR path);
void DeleteContents()
void SetModifiedFlag(BOOL flag=TRUE);
CView
• virtualne funkcije:
void OnUpdate(CView* sender, LPARAM msg, CObject* param);
void OnInitialUpdate();
void OnDraw(CDC*);
klase izvedene iz CView
• izvedene iz CCtrlView:
– CEditView
– CRichEditView
– CListView
– CTreeView
• CScrollView
• CFormView - spojena na resurs dijaloga, podržan DDX i DDV
• izvedene iz CFormView:
– CRecordView
– CDaoRecordView
– COleDBRecordView
– CHTMLView
– CHTMLEditView
CSingleDocTemplate
• odnos dokumenta, pogleda i okvira
BOOL MyApp::InitInstance(){
CSingleDocTemplate* pDocTemplate =
new CSingleDocTemplate(IDR_MAINFRAME,
RUNTIME_CLASS(MyDocument),
RUNTIME_CLASS(MainWindow), // MDI frame
RUNTIME_CLASS(MyView));
AddDocTemplate(pDocTemplate); // CWinApp member
...
}
CView
MDI child
(CxxxView)
CMultiDocTemplate
BOOL MyApp::InitInstance(){
CMultiDocTemplate* pDocTemplate =
new CMultiDocTemplate(IDR_TYPE1,
RUNTIME_CLASS(MyDocument),
RUNTIME_CLASS(CChildFrame), // MDI child
RUNTIME_CLASS(MyView));
AddDocTemplate(pDocTemplate); // CWinApp member
...
}
• štampanje
• registrar
• baze podataka
štampanje
• virtualne funkcije:
void OnPreparePrinting(CPrintInfo*);
void OnBeginPrinting(CDC*, CPrintInfo*);
void OnPrepareDC(CDC*, CPrintInfo*);
void OnPrint(CDC*, CPrintInfo*); // zove OnDraw()
void OnEndPrinting(CDC*, CPrintInfo*);
CPrintInfo
struct CPrintInfo {
CPrintDialog* m_pPD;
BOOL m_bPreview;
BOOL m_bDirect;
BOOL m_bContinuePrinting;
UINT m_nCurPage; • trenutna stranica
UINT m_nNumPreviewPages;
CString m_strPageDesc;
LPVOID m_lpUserData;
CRect m_rectDraw;
BOOL m_bDocObject;
void SetMinPage(UINT nMinPage);
void SetMaxPage(UINT nMaxPage);
UINT GetMinPage() const;
UINT GetMaxPage() const;
UINT GetFromPage() const;
UINT GetToPage() const;
UINT GetOffsetPage() const;
};
registrar / konfiguracijska datoteka (.ini file)
; nwp10.ini
[Font]
Height=12
FaceName=Arial
SetRegistryKey(_T("VEST"));
baze podataka
• 3 načina pristupa bazama podataka:
– ODBC
– DAO
– OLE DB
RecSet rs;
rs.m_strFilter = _T("[id] > 100");
rs.m_strSort = _T("[name] DESC");
rs.Open();
...
RFX (record field exchange)
class RecSet : public CRecordset {
public:
long id;
CString name;
BOOL manager;
...
};
• Fluent UI
• ribbon
Fluent User Interface
• uključuje:
– ribbon
– poboljšane context menije
– bolje screen-tips
– mini toolbar
– keyboard shortcuts
Windows Ribbon Framework
• implementira framework:
– IUIFramework
– IUIRibbon
– IUIContextualUI
– IUISimplePropertySet, IUICollection
– IUIImage, IUIImageFromBitmap
• implementira aplikacija:
– IUIApplication
– IUICommandHandler
– IUICollectionChangedEvent
Ribbon - dijelovi
CMFCRibbonCategory CMFCRibbonPanel
CMFCRibbonApplicationButton
(otvara CMFCRibbonMainPanel)
CMFCRibbonBar
CMFCRibbonStatusBar
ribbon gadgets
Ribbon gadgets
• kontrole:
– CMFCRibbonButton (small, large), CMFCRibbonButtonsGroup, CMFCRibbonGallery
– CMFCRibbonColorButton, CMFCRibbonUndoButton
– CMFCRibbonLabel, CMFCRibbonLinkCtrl
– CMFCRibbonCheckBox
– CMFCRibbonEdit
– CMFCRibbonComboBox, CMFCRibbonFontComboBox
– CMFCRibbonSlider
– CMFCRibbonProgressBar
Ribbon designer
• CMFCRibbonBar::LoadFromResource() za učitavanje