WinAPI BUTTON

SharpShooter
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 6 lat
  • Postów:45
0

Witam ponownie. Ostatnio zacząłem się uczyć WinAPI. Napisałem prostą grę Snake. Teraz chciałbym dołączyć do niej menu. Stworzyłem button Start jednak nie jest on wyświetlany na ekranie (ale istnieje w tym miejscu). Gdy klikne button gra startuje ale button nadal jest w tym miejscu (niewidoczny). Może mi ktoś pomóc? Problem pewnie banalny ale niestety nie dla nowicjusza. Oto mój kod:

Kopiuj
#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

#include <tchar.h>
#include <windows.h>
#include <deque>
#include <ctime>
#include <cstdlib>
#include <mmsystem.h>

static const unsigned WIDTH = 700;
static const unsigned HEIGHT = 500;

void Ruch();
void UaktualnijObraz(HWND hwnd);
void tlo(HWND hwnd);
bool skucha();
void papu(HWND hwnd);
bool bAktywneOkno = true;
void Reset(HWND hwnd);
bool gra = false;

BOOL PlaySound( LPCTSTR pszSound, HMODULE hmod,DWORD fdwSound);
HWND g_GO;

std::deque <POINT> Wspolrzedne_Weza;
POINT jedzenie;
int Size_Snake = 1;
int kierunek = VK_DOWN;

HPEN YellowPen = CreatePen(PS_SOLID, 10,0x00FFFF);
HPEN PapuPen = CreatePen(PS_SOLID, 10, 0x00FF00);
/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
TCHAR szClassName[ ] = _T("CodeBlocksWindowsApp");

int WINAPI WinMain (HINSTANCE hThisInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpszArgument,
                     int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, "snake.ico");
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           _T("Code::Blocks Template Windows App"),       /* Title Text */
           WS_OVERLAPPEDWINDOW, //WS_SYSMENU|WS_CAPTION|WS_SIZEBOX, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           WIDTH,                 /* The programs width */
           HEIGHT,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /*RESET GRY*/
    Reset(hwnd);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
        if (bAktywneOkno){
            if (gra){
                if (!skucha()){
                    Ruch();
                    papu(hwnd);
                    UaktualnijObraz(hwnd);
                    Sleep(10);
                }
            } else {
                /*menu*/
                g_GO = CreateWindowEx( 0, "BUTTON", "Start!",  WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
                    WIDTH/2-75, 200, 150, 30, hwnd, NULL, hThisInstance, NULL );  //            <-- TUTAJ JET MÓJ PROBLEM
            }
        }
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
    case WM_COMMAND:
        Reset(hwnd);
        gra = true;
        break;
    case WM_PAINT:
        break;
    case WM_ACTIVATE:
        if(LOWORD(wParam) == WA_INACTIVE)
           bAktywneOkno = false;
        else bAktywneOkno = true;
        break;
    case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
    default:    /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}


void Ruch()
{
    if (GetAsyncKeyState(VK_UP) && kierunek != VK_UP){
        kierunek = VK_UP;
    }
    else if (GetAsyncKeyState(VK_DOWN) && kierunek != VK_DOWN){
        kierunek = VK_DOWN;
    }
    else if (GetAsyncKeyState(VK_LEFT) && kierunek != VK_LEFT){
        kierunek = VK_LEFT;
    }
    else if (GetAsyncKeyState(VK_RIGHT) && kierunek != VK_RIGHT){
        kierunek = VK_RIGHT;
    }

    POINT temp = Wspolrzedne_Weza[Wspolrzedne_Weza.size()-1];

    switch(kierunek)
    {
    case VK_UP:
        temp.y -=1;
        Wspolrzedne_Weza.push_back( temp );
        break;
    case VK_DOWN:
        temp.y +=1;
        Wspolrzedne_Weza.push_back( temp );
        break;
    case VK_LEFT:
        temp.x -=1;
        Wspolrzedne_Weza.push_back( temp );
        break;
    case VK_RIGHT:
        temp.x +=1;
        Wspolrzedne_Weza.push_back( temp );
        break;

    }
}

void UaktualnijObraz(HWND hwnd)
{
    Wspolrzedne_Weza.pop_front();
    tlo(hwnd);
    HDC hdc = GetDC(hwnd);
    SelectObject(hdc, YellowPen);
    for (int i = 0; i < Wspolrzedne_Weza.size(); i++ )
    {
        MoveToEx(hdc,Wspolrzedne_Weza[i].x,Wspolrzedne_Weza[i].y,NULL);
        LineTo(hdc, Wspolrzedne_Weza[i].x,Wspolrzedne_Weza[i].y);
    }
    SelectObject(hdc, PapuPen);
    Ellipse(hdc, jedzenie.x,jedzenie.y,jedzenie.x+3,jedzenie.y+3);
    ReleaseDC(hwnd,hdc);
}

void tlo(HWND hwnd)
{
    HDC hdcOkno = GetDC(hwnd);
    MoveToEx(hdcOkno, 0,0,NULL);
    HPEN RedPioro = CreatePen(PS_SOLID, 10, 0x0000FF);
    SelectObject(hdcOkno,RedPioro);

    POINT TLO[4];
    TLO[0].x =0;
    TLO[0].y =0;

    TLO[1].x =WIDTH-20;
    TLO[1].y =0;

    TLO[2].x =WIDTH-20;
    TLO[2].y =HEIGHT-40;

    TLO[3].x =0;
    TLO[3].y =HEIGHT-40;

    HBRUSH PedzelBlack = CreateSolidBrush(0x000000); //czarny pedzel xD
    SelectObject(hdcOkno, PedzelBlack);
    Polygon(hdcOkno, TLO, 4);
    DeleteObject(RedPioro);
    DeleteObject(PedzelBlack);

    ReleaseDC(hwnd,hdcOkno);
}

bool skucha()
{
    POINT tmp = Wspolrzedne_Weza[Wspolrzedne_Weza.size()-1];
    if (tmp.x < 10 || tmp.x > WIDTH - 30 || tmp.y < 10 || tmp.y > HEIGHT - 50 ){
        gra = false;
        return true;
    }

    POINT TEMP;
    for (int i = 0; i< (Wspolrzedne_Weza.size()-1); i++){
        TEMP = Wspolrzedne_Weza[i];
        if ( TEMP.x == tmp.x && TEMP.y == tmp.y ){
            gra = false;
            return true;
        }
    }

    return false;
}

void papu(HWND hwnd)
{
    POINT tmp = Wspolrzedne_Weza[Wspolrzedne_Weza.size()-1];
    HDC Ekran = GetDC(hwnd);
    COLORREF kolor = GetPixel(Ekran,tmp.x,tmp.y);

    if( (GetRValue( kolor ) == 0x0 &&  GetGValue( kolor ) == 0xFF && GetBValue( kolor ) == 0x0) ){
        //PlaySound((LPCSTR) "snake.wav", NULL, SND_FILENAME);
        tmp.x = 0;
        tmp.y = 0;
       for (int i =0;i<10;i++)
        Wspolrzedne_Weza.push_front( tmp );
        srand((unsigned) time(NULL));
        jedzenie.x = 20 + rand() % WIDTH;
        jedzenie.y = 20 + rand() % HEIGHT;
    }

    if (jedzenie.x > WIDTH-40 || jedzenie.x < 10 || jedzenie.y > HEIGHT-50 || jedzenie.y <10){
        srand((unsigned) time(NULL));
        jedzenie.x = 15 + rand() % WIDTH;
        jedzenie.y = 15 + rand() % HEIGHT;
    }
}

void Reset(HWND hwnd)
{
        /*reset ogona weza*/
    for (int i = 0; i<Wspolrzedne_Weza.size(); i++)
        Wspolrzedne_Weza.pop_back();

        /*TLO GRY*/
    tlo(hwnd);
        //jedzenie
    srand(time(NULL));
    jedzenie.x = rand() % (WIDTH-20) + 20;
    jedzenie.y = rand() % (HEIGHT-20) + 20;

        /* ustawienie weza*/
    POINT tmp;
    tmp.x = WIDTH/2;
    tmp.y = HEIGHT/2;

    Wspolrzedne_Weza.push_back( tmp );
}

I tak przy okazji. Na czym polega podwójne buforowanie i jak mogę je zastosować w swoim programie żeby nie migał?
Z góry dziękuje za pomoc :)


matrixxx.cba.pl
edytowany 3x, ostatnio: SharpShooter
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:około 15 godzin
  • Lokalizacja:Gorlice
2

Gdzie ty tworzysz ten button? Raczej to powinieneś robić w WindowProcedure przy wywołaniu WM_CREATE.

Kopiuj
BOOL PlaySound( LPCTSTR pszSound, HMODULE hmod,DWORD fdwSound);
HWND g_GO;
HINSTANCE hInst; //dodaj
Kopiuj
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
  return 0;
 hInst = hThisInstance; //dodaj
Kopiuj
switch (message)                  /* handle the messages */
    {
    case WM_CREATE: //dodaj
        g_GO = CreateWindowEx( 0, "BUTTON", "Start!",  WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
                    WIDTH/2-75, 200, 150, 30, hwnd, NULL, hInst, NULL );
        break;
    case WM_COMMAND:
        Reset(hwnd);
//ciach

Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
edytowany 2x, ostatnio: kAzek
SharpShooter
tzn dokładniej jak?
KA
@SharpShooter dokładniej już chyba nie można
SharpShooter
@kAzek Super button już się pokazuje. Ale niestety dopiero po przesunięciu okna. ;/ A kiedy program jest w trakcie gry przycisk nadal istnieje - jest niewidoczny.
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:3 minuty
2
Kopiuj
BOOL PlaySound( LPCTSTR pszSound, HMODULE hmod,DWORD fdwSound);

Nie wiem jaki masz kompilator, ale ja tutaj dostaję

Kopiuj
error C2373: 'PlaySoundW' : redefinition; different type modifiers
Kopiuj
    wincl.hIconSm = LoadIcon (NULL, "snake.ico");

jeśli już się trzymasz makr TEXT() albo _T(), to się trzymaj:

Kopiuj
wincl.hIconSm = LoadIcon (NULL, _T("snake.ico"));
Kopiuj
g_GO = CreateWindowEx( 0, "BUTTON", "Start!",  WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
                                  WIDTH/2-75, 200, 150, 30, hwnd, NULL, hThisInstance, NULL );

jw. brak makra.

Kopiuj
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

Powinno być:

Kopiuj
wincl.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);

bo inaczej twój pędzel nie działa w ogóle.

Kopiuj
    hwnd = CreateWindowEx (
           ...
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           ...
           );

Nie wolno dawać HWND_DESKTOP jako parent window. Główne okno programu powinno jako parent mieć NULL.

Kopiuj
    while (GetMessage (&messages, NULL, 0, 0))

nie nazywaj zmiennej która nie jest kolekcją liczbą mnogą. message, nie “messages”.

Kopiuj
    while (GetMessage (&messages, NULL, 0, 0))
    {
         Sleep(10);    
         ....
         g_GO = CreateWindowEx( ... );
        }
    }

Sleep wewnątrz pętli komunikatow? CreateWindow?
Wywal to wszystko.
Zrób timer, i w timerze odświeżaj stan gry. Tam też sprawdzaj stan klawiszy.
A rysowanie przenieś do WM_PAINT.

SharpShooter
korzystam z Code::Blocks 13.12. Większość błędów które mi tutaj poprawiłeś (za co wielkie dzięki ucze się każde poprawki się przydają oby tylko słuszne) stworzył mi kompilator w momencie utworzenia nowego projektu. Kiedy rysowanie próbowałem zrobić w WM_PAINT program mi crashował =,= W każdym razie dzięki postaram się zastosować Twoje wskazówki :)
Azarien
jeśli błąd z brakiem +1 przy hbrBackground był w szablonie projektu, to mocne WTF.
SharpShooter
Aż sprawdziłem czy to ja czegoś nie poprzestawiałem ;] Ale niestety to nie moja wina. Chyba czas zmienić kompilator, jaki polecacie? xD I takie pytanie do Twoich porad jeszcze. Czyli że wszystko z pętli głównej mam usunąć i przenieść do swich case?
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:3 minuty
1

Czyli że wszystko z pętli głównej mam usunąć i przenieść do swich case?

Są dwie możliwości:

  1. timer (SetTimer) który się odpala co ileś milisekund (ale 10 to raczej za krótko, lepiej 100 albo więcej), odświeża stan gry i odrysowuje okno (InvalidateRect, samo rysowanie zrobione w WM_PAINT).
    zaleta: niskie użycie procka (w okolicach 0%)
    wada: timer nie może być zbyt krótki bo nie wyrobi

  2. pętla czasu rzeczywistego - z użyciem PeekMessage, ale nie może być tam tego sleepa ani CreateWindow.
    zaleta: nie jesteśmy ograniczeni słabą dokładnością timera.
    wady:

  • brak możliwości ustalenia prędkości pętli. trzeba użyć czegoś do pomiaru czasu, np. QueryPerformanceCounter.
  • wysokie użycie procka, w okolicach 100% (na jeden rdzeń, czyli przy quad core Windows pokaże 25%)
SharpShooter
Dzięki za pomoc ale i tak mi coś nie wychodzi. Chyba muszę poszukać jakiejś dobrej książki =,=
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)