Program okienkowy w WinAPI

0

Witam

Jestem w trakcie pisanie programu okienkowego w C++, z wykorzystaniem WinAPI. Oto mój kod:

#include<iostream>
#include<cmath>
#include<windows.h>

const double x0=1.2*M_PI;
const double x1=1.5*M_PI;
const double x2=1.8*M_PI;
double y_0=sin(x0);
double y_1=sin(x1);
double y_2=sin(x2);

LPSTR nazwaklasy="klasa_okna";
MSG komunikat;
HINSTANCE g_hInstance;
HWND okno1, button1, button2, okno_lagrange, okno_newtona, button_lagrange;
int g_nCmdShow;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

void ilagrange();
void inewtona();
double lagrange(double x);

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    WNDCLASSEX wc;
    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 = nazwaklasy;
    wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
    RegisterClassEx(&wc);
    g_hInstance=hInstance;
    g_nCmdShow=nCmdShow;
    //
    okno1=CreateWindowEx(WS_EX_CLIENTEDGE, nazwaklasy, "Interpolacja", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 200, NULL, NULL, hInstance, NULL);
    ShowWindow(okno1, nCmdShow);
    UpdateWindow(okno1);
    button1=CreateWindowEx(0, "BUTTON", "Metoda Lagrange'a", WS_CHILD | WS_VISIBLE, 45, 30, 150, 30, okno1, NULL, hInstance, NULL);
    button2=CreateWindowEx(0, "BUTTON", "Metoda Newtona", WS_CHILD | WS_VISIBLE, 45, 90, 150, 30, okno1, NULL, hInstance, NULL);
    //

    while(GetMessage(&komunikat, NULL, 0, 0))
    {
        TranslateMessage(&komunikat);
        DispatchMessage(&komunikat);
    }
    return komunikat.wParam;
    return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE: DestroyWindow(hwnd); break;
        case WM_DESTROY: PostQuitMessage(0); break;
        case WM_COMMAND:
            if((HWND)lParam==button1) ilagrange();
            if((HWND)lParam==button2) inewtona();
            break;
        default: return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
void ilagrange()
{
    HDC hdcOkno;
    okno_lagrange=CreateWindowEx(WS_EX_CLIENTEDGE, nazwaklasy, "Interpolacja Lagrange'a", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, g_hInstance, NULL);
    hdcOkno=GetDC(okno_lagrange);
    ShowWindow(okno_lagrange, g_nCmdShow);

    TextOut(hdcOkno, 100, 30, "Interpolacja metod¹ Lagrange'a", 30);
    double i=M_PI;
    while(i<2*M_PI)
    {
        SetPixel(hdcOkno, int(100*i)+10, int(100*(lagrange(i)))+200, 0x000000FF);
        i=i+0.0001;
    }
    UpdateWindow(okno_lagrange);
    HWND hText=CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,500, 500, 150, 20, okno_lagrange, NULL, g_hInstance, NULL);
    UpdateWindow(okno_lagrange);
    /*DWORD dlugosc = GetWindowTextLength( hText );
    LPSTR Bufor =( LPSTR ) GlobalAlloc( GPTR, dlugosc + 1 );
    GetWindowText( hText, Bufor, dlugosc + 1 );*/
    
    ReleaseDC(okno_lagrange, hdcOkno);
}
void inewtona()
{
    
}
double lagrange(double x)
{
    return (y_0*(((x-x1)*(x-x2))/((x0-x1)*(x0-x2)))+y_1*(((x-x0)*(x-x2))/((x1-x0)*(x1-x2)))+y_2*(((x-x0)*(x-x1))/((x2-x0)*(x2-x1))));
}

Program działa następująco: w oknie głównym programu znajdują się dwa przyciski. Po wybraniu przycisku wywoływana jest odpowiednia unkcja (na razi zrobiłem obsługę tylko funkcji interpolacja Lagrange'a). W funkcji tworzone jest nowe okienko, w którym rysowany jest wykres funkcji oraz pojawia się TextBox.
Mam następujące problemy:

  1. Chciałbym, aby tylko zamknięcie głównego okna programu powodowało zakończenie programu, a nie tak jak teraz, że zamknięcie dowolnego okna powoduje zakończenie programu.
  2. Nie wiem jaki sposób odczytać liczbę wpisaną do TextBoxa i wyświetlić ją np. jako MessageBox (dokładnie ma wyśweitlać wartość funkcji w podanym punkcie, ale jak będę wiedział jak wyświewtlić tekst wpisany do TextBoxa to będę potrafił wyświetlić też wartość funkcji.
  3. Jako, że jest to mój pierwszy program okienkowy, to prosiłbym o sprawdzenie ogólnej poprawności kodu :)

Będę wdzięczny za wszelkie sugestie i rady.

Pozdrawiam

0

Został jeszcze tylko jeden problem :)
Chciałbym, aby tylko zamknięcie (krzyżykiem) głównego okna programu powodowało zakończenie programu. Obecnie zamknięcie dowolnego okna powoduje zakończenie programu.
Gdy dodałem w pętli komunikatów zamiast case WM_DESTROY: PostQuitMessage(0); break; wstawiłem case WM_DESTROY: if((HWND)lParam==okno1) PostQuitMessage(0); break;, zamknięcie żadnego okienka nie powodowało zakończenia programu (okno1 to główne okno programu).

Cały kod programu:

#include<iostream>
#include<cmath>
#include<windows.h>
#include<string>

const long double x0=1.2*M_PI;
const long double x1=1.5*M_PI;
const long double x2=1.8*M_PI;
long double y_0=sin(x0);
long double y_1=sin(x1);
long double y_2=sin(x2);
long double f_x0_x1;
long double f_x1_x2;
long double f_x0_x1_x2;
long double a0, a1, a2;

LPSTR nazwaklasy="klasa_okna";
MSG komunikat;
HINSTANCE g_hInstance;
HWND okno1, button1, button2, okno_lagrange, okno_newtona, button_lagrange;
int g_nCmdShow;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

void ilagrange();
void inewtona();
long double lagrange(long double x);
long double newton(long double x);

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    y_0=sin(x0); //wartosc funkcji sin w punkcie x0
    y_1=sin(x1); //wartosc funkcji sin w punkcie x1
    y_2=sin(x2); //wartosc funkcji sin w punkcie x2
    f_x0_x1=(sin(x1)-sin(x0))/(x1-x0); //iloraz roznicowy I rzedu
    f_x1_x2=(sin(x2)-sin(x1))/(x2-x1); //iloraz roznicowy I rzedu
    f_x0_x1_x2=(f_x1_x2-f_x0_x1)/(x2-x1); //iloraz roznicowy II rzedu
    a0=y_0;
    a1=f_x0_x1;
    a2=f_x0_x1_x2/2;

    WNDCLASSEX wc;
    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 = nazwaklasy;
    wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION );
    RegisterClassEx(&wc);
    g_hInstance=hInstance;
    g_nCmdShow=nCmdShow;
    //
    okno1=CreateWindowEx(WS_EX_CLIENTEDGE, nazwaklasy, "Interpolacja", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 200, NULL, NULL, hInstance, NULL);
    ShowWindow(okno1, nCmdShow);
    UpdateWindow(okno1);
    button1=CreateWindowEx(0, "BUTTON", "Metoda Lagrange'a", WS_CHILD | WS_VISIBLE, 45, 30, 150, 30, okno1, NULL, hInstance, NULL);
    button2=CreateWindowEx(0, "BUTTON", "Metoda Newtona", WS_CHILD | WS_VISIBLE, 45, 90, 150, 30, okno1, NULL, hInstance, NULL);
    //

    while(GetMessage(&komunikat, NULL, 0, 0))
    {
        TranslateMessage(&komunikat);
        DispatchMessage(&komunikat);
    }
    return komunikat.wParam;
    return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CLOSE: DestroyWindow(hwnd); break;
        case WM_DESTROY: PostQuitMessage(0); break;
        case WM_COMMAND:
            if((HWND)lParam==button1) ilagrange();
            if((HWND)lParam==button2) inewtona();
            break;
        default: return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
void ilagrange()
{
    HDC hdcOkno;
    okno_lagrange=CreateWindowEx(WS_EX_CLIENTEDGE, nazwaklasy, "Interpolacja Lagrange'a", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, okno1, NULL, g_hInstance, NULL);
    hdcOkno=GetDC(okno_lagrange);
    ShowWindow(okno_lagrange, g_nCmdShow);

    TextOut(hdcOkno, 150, 30, "Interpolacja metod¹ Lagrange'a funkcji sin(x) w przedziale [PI, 2*PI]", 69);
    double i=M_PI;
    while(i<2*M_PI)
    {
        SetPixel(hdcOkno, int(100*i)-50, int(-100*(lagrange(i)))+200, 0x000000FF);
        i=i+0.0001;
    }
    POINT stary_punkt;
    MoveToEx( hdcOkno, 150, 200, & stary_punkt );
    LineTo( hdcOkno, 700, 200 );
    TextOut(hdcOkno, 150, 400, "Blad interpolacji w punkcie 4:", 30);
    double blad=sin(4)-lagrange(4);
    char tblad[9];
    sprintf (tblad, "%lf", blad);
    strcat (tblad, "1");
    sscanf (tblad, "%lf", &blad);
    TextOut(hdcOkno, 350, 400, tblad, 9);
    UpdateWindow(okno_lagrange);
    ReleaseDC(okno_lagrange, hdcOkno);
}
void inewtona()
{
    HDC hdcOkno;
    okno_newtona=CreateWindowEx(WS_EX_CLIENTEDGE, nazwaklasy, "Interpolacja Newtona", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, okno1, NULL, g_hInstance, NULL);
    hdcOkno=GetDC(okno_newtona);
    ShowWindow(okno_newtona, g_nCmdShow);

    TextOut(hdcOkno, 150, 30, "Interpolacja metoda Newtona funkcji sin(x) w przedziale [PI, 2*PI]", 66);
    double i=M_PI;
    while(i<2*M_PI)
    {
        SetPixel(hdcOkno, int(100*i)+10, int(-100*(lagrange(i)))+200, 0x000000FF);
        i=i+0.0001;
    }
    POINT stary_punkt;
    MoveToEx( hdcOkno, 150, 200, & stary_punkt );
    LineTo( hdcOkno, 700, 200 );
    TextOut(hdcOkno, 150, 400, "Blad interpolacji w punkcie 4:", 30);
    double blad=sin(4)-newton(4);
    char tblad[9];
    sprintf (tblad, "%lf", blad);
    strcat (tblad, "1");
    sscanf (tblad, "%lf", &blad);
    TextOut(hdcOkno, 350, 400, tblad, 9);
    UpdateWindow(okno_newtona);
    ReleaseDC(okno_newtona, hdcOkno);
}
long double lagrange(long double x) //funkcja zwraca wartosc wielomianu Lagrange'a w punkcie x
{
    return (y_0*(((x-x1)*(x-x2))/((x0-x1)*(x0-x2)))+y_1*(((x-x0)*(x-x2))/((x1-x0)*(x1-x2)))+y_2*(((x-x0)*(x-x1))/((x2-x0)*(x2-x1))));
}
long double newton(long double x) //funkcja zwraca wartosc wielomianu Newtona w punkcie x
{
    return(a0+a1*(x-x0)+a2*(x-x0)*(x-x1));
}

Będę wdzięczny za wszelkie wskazówki

Pozdrawiam

1
  1. twój program w takiej dosłownej postaci nie kompiluje się ani pod VC++ ani pod GCC; jakiego kompilatora używasz?
  2. wszystke twoje okna mają tę samą klasę, więc wszystkie mają tę samą procedurę okna, więc wszystkie na WM_DESTROY wykonują PostQuitMessage(0);, co przerywa pętlę komunikatów while(GetMessage(...)).

Odpowiedź: zdefiniuj inną klasę dla okien podrzędnych.

"klasa okna" to jakby rodzaj okna. Okna zasadniczo różne powinny mieć różną klasę (WNDCLASSEX).
Okna takie same albo generalnie podobne mogą mieć tę samą klasę.
Okno główne twojego programu jest istotnie inne od dwóch okienek podrzędnych.

  1. zawartość okna należy rysować w odpowiedzi na WM_PAINT, a nie jednorazowo po otwarciu okna. teraz jak zminimalizujesz okno i przywrócisz, zawartość może zniknąć.
0

Dziękuję bardzo za odpowiedź
Korzystam z Code::Blocks 10.05

Zdefiniowałem drugą klasę i już nie ma problemu z zamykaniem programu

Jeśli chodzi o rysowanie okna to w odpowiedzi na WM_PAINT mam wywoływać funkcje SetPixel, TextOut itd.? Jeśli tak to w jaki sposób rozpoznać, które okno wysłało komunikat (ta klasa obsługuje dwa okna)?

0

Nie prościej DialogBoxParam (jedna funkcja) zamiast RegisterClassEx i pełno CreateWindowEx?

1 użytkowników online, w tym zalogowanych: 0, gości: 1