/************/ /* easyw.c */ /***************************************************************************** Yksinkertainen Windows-runko näyttöön tulostavien ohjelmien tekemiseksi. Korvaa EasyWin-kirjaston siinä mielessä että tämä toimii myös Win32:ssa, missä EasyWin ei toimi! 13.1.1993 & 3.8.1994 /vl ( Ei ole vielä takuutuote! ) Käyttö: ======= Ohjelmaan lisää: #include "easyw.h" // Miel. :n tilalle (tai ainakin jälkeen). Projektiin: pääohjelma (jossa main-funktio, ei winmain) ALI\easyw.c Funktiot ja makrot (->): ======================== show(char *s) - tulostaa näyttöön merkkijonon printf(fmt,...) - kuten oikea printf, mutta samaan ikkunaan kuin show scanf(fmt,...) - kuten oikea scanf (muista &-merkit muuttujiin!) wgets(s,n,f) - kuten fgets, paitsi jos luetaan stdin niin näytetään oletuksena jonon sisältö (myös NULL => stdin), eikä jätä \n rivin loppuun stdin-lukemisessa fgets -> wgets N_S(s) -> s,sizeof(s) InitEasyW(hInst,nCmdShow) - alustaa ikkunan (tehdään automaattisesti jollei määritellä vakiota NO_WINMAIN, paluttaa ikkunan kahvan tai NULL jos ei onnistu EASYW_RETNOW - arvo, jolla ikkuna loppuu heti kun pääohjelmasta palataan SetEasyShowMode(m) - asettaa missä moodissa näyttö päivitetään Palauttaa edellisen moodin (tyyppi eEasyModes) Mahdollisuudet: EASY_HIDE - piilotetaan jokaisen tulostuksen aluksi ja palautetaan inputissa - välkkuu inputin yhteydessä jos peräkkäin scanf, printf + nopea EASY_AUTO_SHOW - piilotetaan jos näyttöön tulos- oletus tetaan paljon kerralla (5 kertaa tai yli 200 merkkiä) ja näyttö palautetaan näkyviin kun input + aika hyvä - toiminnan vakiot (200, 5) aina kompromisseja, eivatka aina ole hyvia - jos pitkia tulosteita ja sitten tarvittaisiinkin näyttaa ikkuna, niin eipa näykkään automaattisesti! EASY_MAN_SHOW - näyttö on näkyvissä kokoajan, - hidas pitkissä tulosteissa + parempi kuin EASY_HIDE scanf, printf, scanf -tilanteissa Funktiolla voidaan myös vaihtaa moodia tarvittaessa. Eli pitkiin tulostuksiin voidaan laittaa EASY_HIDE ja sitten ennen inputtia tai lyhyitä tulostuksia EASY_AUTO_SHOW tai EASY_MAN_SHOW. _SHOW -loppuisilla arvoilla voidaan ikkunan aina saada näkyviin. Esim. jos oletus on päällä ja halutaan käyttää kutsua KysyJono (strlib.h), niin ennen tätä vanhat tulosteet on saatava näkyviin esim. kutsulla SetEasyShowMode(EASY_AUTO_SHOW); KysyJono(... Määrittelyt: ============ NO_WINMAIN - käännetään ohjelma siten, että WinMain on tehtävä itse ja kutsuttava aikanaan alustusta InitEasyW RETMAIN - jos määritelty, lopettaa kun pääohjelmasta palataan Vihjeitä: ========= show("\n"); tai printf("\n"); siirtyy uudelle riville. show("\f"); tai printf("\f"); tyhjentää näytön Esimerkki: ========== ----------------------------------------------------------------------------- // easytest.c #include "easyw.h" int main(void) { char s[40] = "Kana"; double d=123.45; int i=0,kpl=20; printf("Kissa\n\n"); printf("istuu\n puussa\n"); printf("Anna kappalemäärä>"); scanf("%d",&kpl); printf("Tavaraa %d kpl\n",kpl); printf("Anna hinta >"); scanf("%lf",&d); printf("Hinta %lg mk\n",d); printf("Nyt syöttele merkkijonoja, kunnes ESC lopettaa!\n"); do { printf("Jono %d >",i++); } while ( fgets(N_S(s),stdin) ); return 0; } ----------------------------------------------------------------------------- Ongelmia: ========= 1. Ruudun ReadOnly ei toimi, jollei jotakin .RC-tiedostoa ole otettu mukaan! Tämä koska muuten resurssit käsitellään Windows 3.0:n mukaan ja täällä ei ole ES_READONLYa! Tai sitten lippu pitää asettaa explisiittisesti kutsulla: SendDlgItemMessage(hWnd,id,EM_SETREADONLY,TRUE,0); Tehty näin (mutta kesti kauan ennenkuin löytyi)! 2. Hidas jos näyttää koko ajan! Listbox on aika nopea jos ei siirrytä kokoajan viimeiselle riville (tosin on EDITkin nopea jos päivityksiä ei näytetä) Tehty eri päivitysmoodeja, jottei turhaan päivitä näyttöä. 3. Editoinnissa print-ikkuna pitäsi päivittää harvemmin, ei joka muutoksella. Esim. timerilla? *****************************************************************************/ #include #include /* Message crakers */ #include /* fgets jne. */ #include /* abort */ #include /* Vaikka mitä */ #include /* argc, argv */ #include /* ... käsittely */ #include "easyw.h" int main(int, char **); /****************************************************************************/ /* Kontrollien paikat ja leveydet näytöllä */ #define ReadH 20 #define ButW 50 #define MsgW 60 #define ButX 0 #define BOkX (ButX+ButW) #define MsgX (BOkX+ButW) #define EdiX (MsgX+MsgW) #define EditW (rc.right-ButW-MsgW) #define HIDELIMIT 200 #define HIDECOUNT 5 /****************************************************************************/ static struct {/*----- Aliohjelmien väliset "Globaalit" muuttujat:----------*/ HWND hWnd; /* Pääikkunan kahva */ int Read; /* Onko Read menossa */ int Cancel; /* Painettiinko readin aikana Cancel */ int waiting_ALTF4; /* Onko odottamassa ALT-F4:n painamista */ int ReadPos; /* Paikka näyttöikkunassa lukemisen alkaessa */ int size; /* Tällä hetkellä luettavan jonon koko */ eEasyModes showmode;/* Onko näyttämismoodi päällä vai ei */ int hidecount; /* Montako tulostusta ilman kysymystä */ int hide; /* Onko ikkuna piilossa! */ } EasyG; /****************************************************************************/ /* Seuraavat makrot olettavat että on isäikkunan muuttuja hWnd */ /* Makrot on tehty, jotta olioihin voitaisiin viitata id:llä eikä hWnd:llä */ #define SWP_F ( SWP_NOZORDER | SWP_NOSIZE ) #define H(id) GetDlgItem(hWnd,id) #define MOVEWIN(id,x,y) SetWindowPos(H(id),0,x,y,0,0,SWP_F) #define MOVSWIN(id,x,y,cx,cy) MoveWindow(H(id),x,y,cx,cy,TRUE); #define SHOWWIN(id) ShowWindow(H(id),SW_SHOW) #define HIDEWIN(id) ShowWindow(H(id),SW_HIDE) #define SETFOC(id) SetFocus(H(id)) #define SETTEXT(id,s) SetWindowText(H(id),s) #define GETTEXT(id,s,n) GetWindowText(H(id),s,n) #define GETTEXTS(id,s) GetWindowText(H(id),s,sizeof(s)) #define SETSEL(id,b,e) Edit_SetSel(H(id),b,e) #define REPLACESEL(id,s) Edit_ReplaceSel(H(id),s) #define SELALL(id) SETSEL(id,0,32001) #define SELLAST(id) SETSEL(id,32000,32001) #define SELFROM(id,f) SETSEL(id,f,32001) #define GETLASTPOS(id) (SELLAST(IDC_PRINTWND),LOWORD(Edit_GetSel(H(id)))) #define IS_END() if ( EasyG.waiting_ALTF4 ) SendMessage(hWnd,WM_DESTROY,0,0); /****************************************************************************/ static int HandleMessage(HWND hWnd,MSG *msg) { if ( IsDialogMessage(hWnd,msg) ) return 0;; TranslateMessage(msg); /* Tulkitaan virtuaaliset näp. koodit */ DispatchMessage(msg); /* Lähetetään viesti ikkunalle */ return 0; } /****************************************************************************/ #define PEEK_MESSAGE() /* Viestisilmukka */ \ { MSG msg; \ while ( PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE) ) \ HandleMessage(hWnd,&msg); \ } /****************************************************************************/ static int UpdatePanes(HWND hWnd) /* Siirretään kukin ikkuna oikealle paikalleen ja Read-tilan mukaan */ /* näytetään tai hävitettään turhat kontrollit */ { RECT rc; GetClientRect(hWnd,&rc); MOVSWIN(IDC_PRINTWND,rc.left,rc.top,rc.right,rc.bottom-ReadH); MOVSWIN(IDC_PRINTWND,rc.left,rc.top,rc.right,rc.bottom-ReadH); MOVEWIN(CM_BREAK ,rc.left+ButX,rc.bottom-ReadH); MOVEWIN(CM_OK ,rc.left+BOkX,rc.bottom-ReadH); if ( !EasyG.Read ) { /* Ei Read-tila */ if ( EasyG.hide ) HIDEWIN(IDC_PRINTWND); else SHOWWIN(IDC_PRINTWND); HIDEWIN(IDC_EDITWND); HIDEWIN(IDC_MSGWND); return NULL; } /* Read-tilassa näkyviin myös Edit-ikkuna ja hopute-ikkuna */ MOVSWIN(IDC_EDITWND ,rc.left+EdiX,rc.bottom-ReadH+1,EditW,ReadH); MOVEWIN(IDC_MSGWND ,rc.left+MsgX,rc.bottom-ReadH+1); SHOWWIN(IDC_PRINTWND); SHOWWIN(IDC_EDITWND); SHOWWIN(IDC_MSGWND); SETFOC(IDC_EDITWND); return NULL; } /****************************************************************************/ static int CreatePanes(HWND hWnd) { HINSTANCE hInstance = GetWindowInstance(hWnd); CreateWindow("Edit","", WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_READONLY | WS_TABSTOP | ES_AUTOVSCROLL ,0,1,0,1, hWnd,(HMENU)IDC_PRINTWND, hInstance,NULL); CreateWindow("Edit","", WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP ,0,0,400,ReadH, hWnd,(HMENU)IDC_EDITWND, hInstance,NULL); CreateWindow("STATIC","Syötä >", WS_CHILD | SS_RIGHT ,0,0,MsgW,ReadH, hWnd,(HMENU)IDC_MSGWND, hInstance,NULL); CreateWindow("BUTTON","&Break", WS_BORDER | WS_CHILD | WS_VISIBLE ,0,0,ButW,ReadH, hWnd,(HMENU)CM_BREAK, hInstance,NULL); CreateWindow("BUTTON","&OK", WS_BORDER | WS_CHILD | WS_VISIBLE ,0,0,ButW,ReadH, hWnd,(HMENU)CM_OK, hInstance,NULL); (void)Edit_SetReadOnly(GetDlgItem(hWnd,IDC_PRINTWND), TRUE); return UpdatePanes(hWnd); } /****************************************************************************/ eEasyModes SetEasyShowMode(eEasyModes mode) { eEasyModes old = EasyG.showmode; EasyG.hidecount = 0; EasyG.hide = 0; EasyG.showmode = mode; if ( mode == EASY_HIDE ) EasyG.hide = 1; UpdatePanes(EasyG.hWnd); return old; } /****************************************************************************/ static int do_hide(HWND hWnd) { HIDEWIN(IDC_PRINTWND); EasyG.hide = 1; return 1; } /****************************************************************************/ static int set_read(int n) { HWND hWnd = EasyG.hWnd; EasyG.size = n; EasyG.ReadPos = GETLASTPOS(IDC_PRINTWND); EasyG.hidecount = 0; EasyG.hide = 0; EasyG.Read = 1; EasyG.Cancel = 0; UpdatePanes(EasyG.hWnd); return 0; } /****************************************************************************/ static int set_no_read(void) { if ( EasyG.showmode == EASY_HIDE ) EasyG.hide = 1; EasyG.Read = 0; UpdatePanes(EasyG.hWnd); return 0; } /****************************************************************************/ static int UpdatePrintWnd(HWND hWnd) /* Päivitetään sama syöttö myös tulosikkunaan */ { static char s[200]; SELFROM(IDC_PRINTWND,EasyG.ReadPos); GETTEXT(IDC_EDITWND,s,min(sizeof(s),EasyG.size)); REPLACESEL(IDC_PRINTWND,s); return 0; } /****************************************************************************/ static int ShouldWeHide(HWND hWnd,const char *s) { if ( EasyG.showmode == EASY_MAN_SHOW ) return 0; if ( EasyG.showmode == EASY_HIDE ) return do_hide(hWnd); /* Auto mode: */ if ( EasyG.hidecount >= HIDECOUNT ) return do_hide(hWnd); if ( strlen(s) >= HIDELIMIT ) return do_hide(hWnd); EasyG.hidecount++; return 0; } /****************************************************************************/ void show(char *S) { HWND hWnd = EasyG.hWnd; char *p,*s = S; static char line[200]; int oli_FF = 0; int i=0; while ( ( p = strchr(s,'\f') ) != NULL ) { /* Etsitään viimeinen FormFeed */ s = p + 1; oli_FF = 1; } if ( oli_FF ) SETTEXT(IDC_PRINTWND,""); SELLAST(IDC_PRINTWND); ShouldWeHide(hWnd,s); /* Käydään läpi aina seuraavaan \n asti, jonka tilalle täytyy */ /* tulostaa \r\n */ while ( ( p = strchr(s,'\n') ) != NULL ) { *p = 0; strncpy(line,s,sizeof(line)-2); *p = '\n'; line[sizeof(line)-3] = 0; REPLACESEL(IDC_PRINTWND,strcat(line,"\r\n")); s = p + 1; i++; if ( i > 2 ) { i=0; PEEK_MESSAGE(); } } if ( *s ) REPLACESEL(IDC_PRINTWND,s); PEEK_MESSAGE(); /* Viestisilmukka jotta voidaan kesk. kesken tulostuksen */ } /****************************************************************************/ /* "ANSI-C" funktiot */ /****************************************************************************/ static char AnsiS[10000]; int printf(const char *fmt, ...) { int ret; va_list ap ; va_start(ap,fmt); ret = vsprintf(AnsiS,fmt,ap); show(AnsiS); va_end(ap); return ret; } char *wgets(char *s,int n,FILE *f) { // if ( KysyJono("Anna syöte","",N_S(s)) <= 0 ) return 0; MSG msg; HWND hWnd = EasyG.hWnd; if ( f != stdin && f ) return fgets(s,n,f); set_read(n); SETTEXT(IDC_EDITWND,s); SELALL(IDC_EDITWND); while ( GetMessage(&msg,NULL,NULL,NULL) && EasyG.Read ) HandleMessage(hWnd,&msg); set_no_read(); if ( EasyG.Cancel ) { SETTEXT(IDC_EDITWND,""); show("\n"); return NULL; } GETTEXT(IDC_EDITWND,s,n); show("\n"); return s; } int scanf(const char *fmt, ...) { int ret; va_list ap; AnsiS[0]=0; if ( wgets(N_S(AnsiS),stdin) == NULL ) return EOF; if ( AnsiS[0] == 0 ) return 0; va_start(ap,fmt); ret = vsscanf(AnsiS,fmt,ap); va_end(ap); return ret; } /****************************************************************************/ /* "ANSI-C" funktiot loppuivat */ /****************************************************************************/ /****************************************************************************/ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_SIZE: return UpdatePanes(hWnd); case WM_CREATE: return CreatePanes(hWnd); case WM_COMMAND: switch ( GET_WM_COMMAND_ID(wParam,lParam) ) { case IDC_EDITWND: { if ( GET_WM_COMMAND_CMD(wParam,lParam) == EN_CHANGE ) UpdatePrintWnd(hWnd); break; } #if 0 case IDC_PRINTWND: { LPARAM lp; lp=GET_WM_COMMAND_CMD(wParam,lParam); if ( lp == EN_HSCROLL || lp == EN_VSCROLL ) { InvalidateRect(hWnd,NULL,0); } break; } #endif case CM_OK: case IDOK: IS_END(); EasyG.Read=0; EasyG.Cancel=0; return NULL; case IDCANCEL: IS_END(); EasyG.Read=0; EasyG.Cancel=1; return NULL; case CM_BREAK: IS_END(); EasyG.Read=0; EasyG.Cancel=2; return NULL; } /* wParam */ break; /* WM_COMMAND */ case WM_NEXTDLGCTL: SETFOC(IDC_EDITWND); return NULL; case WM_CLOSE: /* Lukemisen aikana sulkeminen vain Edit-ikkunasta */ if ( !EasyG.Read ) break; if ( GetFocus() == H(IDC_EDITWND) ) break; EasyG.Read=0; EasyG.Cancel=2; return NULL; case WM_DESTROY: /* Viesti: ikkuna hävitetään */ PostQuitMessage(0); if ( !EasyG.waiting_ALTF4 ) abort(); /* Jos ei sammutettu oikein!*/ return NULL; default: /* Antaa Windowsin käsitellä muut */ break; } return DefWindowProc(hWnd, message, wParam, lParam); } /****************************************************************************/ HWND InitEasyW(HINSTANCE hInstance,int nCmdShow) { static initdone = 0; WNDCLASS wc; /* Ikkunaluokka */ if ( initdone ) return 0; wc.style = NULL; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "EasyWClass"; if (!RegisterClass(&wc)) return NULL; EasyG.hWnd = CreateWindow("EasyWClass",_argv[0],WS_OVERLAPPEDWINDOW, 0,0,800,600, NULL,NULL,hInstance,NULL); if (!EasyG.hWnd) return NULL; ShowWindow(EasyG.hWnd, nCmdShow); /* Näytetään ikkuna */ initdone = 1; return EasyG.hWnd; } #ifndef NO_WINMAIN /****************************************************************************/ int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { #pragma argsused HWND hWnd; MSG msg; int ret; int now = 0; # ifdef RETMAIN /* Lopetetaanko heti pääohjelman jälkeen? */ now = 1; # endif if ( ( hWnd = InitEasyW(hInstance,nCmdShow) ) == NULL ) return 1; ret = main(_argc,_argv); if ( ret == EASYW_RETNOW || now ) SendMessage(hWnd,WM_DESTROY,0,0); EasyG.waiting_ALTF4 = 1; SetWindowText(hWnd,"Paina Alt-F4, jotta ikkuna häviää"); SetEasyShowMode(EASY_MAN_SHOW); SETFOC(IDC_PRINTWND); while ( GetMessage(&msg,NULL,NULL,NULL) ) HandleMessage(hWnd,&msg); return ret; } #endif #if 0 int main(void) { int i; for (i=0; i<40; i++) printf("i = %05d ========= \n",i); return 0; } #endif