Zmiana rozmiaru czcionki w kontrolce Edit/Static

0

Jak w temacie załączam mój kod, który nie funkcjonuje jak powinien. (sorry za spagetti code)
Odwiedziłem kilka stronek, no i z ich odpowiedzi próbowałem jakoś rozwiązać problem. (wydaje mi się że problem leży bardziej w logice programu niż w samym kodzie, być może odświeżając zmieniam ponownie czcionkę, pragnę zaznaczyć że Edit/Static ma się odrysowywać co sekundę)

#include <time.h>
#include <stdio.h>
#include <windows.h>


//===================================================
//GLOBAL VARIABLE
//===================================================
HINSTANCE main_hinst;
MSG main_msg;
HWND main_hwnd;
HWND main_editbox;
HFONT main_font;// = CreateFont(-17,0,0,0,FW_NORMAL,0,0,0,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE,"Courier New");
HFONT tmp_font;
HDC main_hdc;

char s_time[9];

RECT screen_rect;

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_CREATE:
        {
            GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, NULL, "hh':'mm':'ss", s_time, 9);
            //=========================================
            LOGFONT lf;
            tmp_font = (HFONT)SendMessage(main_editbox, WM_GETFONT, 0, 0);
            if(main_hdc = GetDC(main_editbox))
                {
                    if (tmp_font == NULL)
                    {
                        tmp_font = (HFONT)GetStockObject(SYSTEM_FONT);
                        GetObject(tmp_font, sizeof(LOGFONT),&lf);
                        lf.lfQuality = DEFAULT_QUALITY;
                        lf.lfWidth = 0;
                    }
                    else
                    {
                        GetObject(tmp_font, sizeof(LOGFONT),&lf);
                        int dpi = GetDeviceCaps(main_hdc, LOGPIXELSY);
                        lf.lfHeight = -MulDiv(20, dpi, dpi);
                        //lf.lfHeight = -MulDiv(20, GetDeviceCaps(main_hdc, LOGPIXELSY), 72);
                        main_font = CreateFontIndirect(&lf);
                        SendMessage(main_editbox, WM_SETFONT, (WPARAM)main_font, MAKELPARAM(TRUE,0));
                    }
                }
            //SendMessage(main_editbox,WM_SETFONT,(WPARAM)main_font,MAKELPARAM(TRUE, 0));
            break;
        }
        case WM_PAINT:
        {
            SendMessage(main_editbox, WM_SETTEXT, 9, (LPARAM)s_time);
            Sleep(1000);
            break;
        }
        case WM_DESTROY:
        {
            ReleaseDC(main_editbox, main_hdc);
            DeleteObject(main_font);
            PostQuitMessage(0);
            return 0;
        }
    }
    RedrawWindow(main_hwnd, NULL, NULL, RDW_INTERNALPAINT|RDW_ALLCHILDREN);
    return DefWindowProc (hwnd, message, wParam, lParam);
}


int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASS main_wc;
    const char *AppName = "Manor Timer";

    memset(&main_wc,0,sizeof(WNDCLASS));
    main_wc.style         = CS_HREDRAW | CS_VREDRAW;
    main_wc.lpfnWndProc   = WndProc;
    main_wc.hInstance     = main_hinst;
    main_wc.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    main_wc.hCursor       = LoadCursor (NULL, IDC_ARROW);
    main_wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    main_wc.lpszMenuName  = NULL;
    main_wc.lpszClassName = AppName;

    if (!RegisterClass (&main_wc))
    {
        MessageBox (NULL , "This program requires Windows NT!", "Manor Timer", MB_ICONERROR);
        return 0;
    }

    main_hwnd = CreateWindow (AppName,                      // window class name
                              TEXT ("Manor Timer"), // window caption
                              WS_BORDER|WS_POPUP,          // window style
                              CW_USEDEFAULT,                // initial x position
                              CW_USEDEFAULT,                // initial y position
                              110,                          // initial x size
                              50,                          // initial y size
                              HWND_DESKTOP,                 // parent window handle
                              NULL,                         // window menu handle
                              main_hinst,                   // program instance handle
                              NULL);                        // creation parameters

    main_editbox = CreateWindow("EDIT", s_time, WS_CHILD|WS_VISIBLE, 5, 5, 100, 40, main_hwnd, 0, main_hinst, 0);

    ShowWindow(main_hwnd, SW_SHOW);
    UpdateWindow(main_hwnd);

    while(GetMessage(&main_msg, NULL, 0, 0))
    {
        GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, NULL, "hh':'mm':'ss", s_time, 9);
        TranslateMessage (&main_msg);
        DispatchMessage (&main_msg);
    }
    return main_msg.wParam ;
}


0

Jest dużo błędów wynikających zapewne z copy-paste nie całkiem poprawnych kawałków, i z nieczytania dokumentacji.

     main_wc.hbrBackground = (HBRUSH)COLOR_WINDOW;

Powinno być (HBRUSH)(COLOR_WINDOW+1).

        MessageBox (NULL , "This program requires Windows NT!", "Manor Timer", MB_ICONERROR);

No co ty nie powiesz ;-)
Sprawdzanie wyniku RegisterClass() można pominąć, bo po pierwsze, nie ma powodu by się nie udało, a po drugie, jeśli się nie uda, to potem się nie uda CreateWindow, więc i tak będziesz wiedział.
A właśnie przydałoby się sprawdzanie wyniku CreateWindow, którego nie masz.

                              HWND_DESKTOP,                 // parent window handle

Nie wolno dawać HWND_DESKTOP jako parent window. Jeśli nie chcesz parenta to dajesz NULL.

        GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, NULL, "hh':'mm':'ss", s_time, 9);

Wywal to z pętli komunikatów. Zrób timer z okresem co sekundę i w nim odrysowuj czas.

    RedrawWindow(main_hwnd, NULL, NULL, RDW_INTERNALPAINT|RDW_ALLCHILDREN);

Wywal to z WndProc :-(

0

Ten kod jest niechlujny (tzn nie wiem gdzie mogę dawać funkcje zarządzające oknem czy w WndProc, czy może w pętli komunikatów)... trochę zabolało to copy-paste... tylko część odpowiadającą za zmianę czcionki, która nie działa byłem zmuszony skopiować...
Natomiast nigdzie w opisie funkcji CreateWindow() nie znalazłem informacji, że nie wolno podawać uchwytu pulpitu, ale domniemam, że Pana uwagi oparte są na długoletnim doświadczeniu, dziękuję za krytykę

0
        case WM_PAINT:
        {
            SendMessage(main_editbox, WM_SETTEXT, 9, (LPARAM)s_time);
            Sleep(1000);
            break;
        }

"zalagujesz" sobie odrysowywanie calego interfejsu ..

0

Polecam użycie jakiegoś pomocniczego frameworka do klepania tych okienek w winapi. Poniżej przykład użycia Windows Template Library. Jest to taka bardzo lekka wersja MFC zbudowana na ATL.

Link do najnowszej wersji: http://sourceforge.net/projects/wtl/files/WTL%208.1/WTL%208.1.12085/wtl81_12085.zip/download
Nie trzeba niczego z niczym linkować, WTL to same nagłówki. Rozwijane przez Microsoft, stosowane np. przez Google w Chrome na Windows.

#include <Windows.h>
#include <atlbase.h>
#include <atlapp.h>
#include <atlctrls.h>
#include <atlcrack.h>

#include <memory>

typedef CWinTraits<WS_OVERLAPPED | WS_SYSMENU, WS_EX_OVERLAPPEDWINDOW> MainFormWindowTraits;

class MainForm : public CWindowImpl<MainForm, CWindow, MainFormWindowTraits>
{
    BEGIN_MSG_MAP(MainForm)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_CLOSE(OnClose)
        MSG_WM_DESTROY(OnDestroy)
        MSG_WM_CTLCOLORSTATIC(OnCtlColorStatic)
        MSG_WM_ERASEBKGND(OnBackgroundPaint)
        MSG_WM_TIMER(OnTimer)
    END_MSG_MAP()

    CBrush _backgroundBrush;
    
    CStatic _static;
    CFont _staticFont;

    int OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        _backgroundBrush.CreateSolidBrush(RGB(87, 184, 240));

        _staticFont.CreateFont(-MulDiv(50, GetDeviceCaps(CDC(GetDC()), LOGPIXELSY), 72), 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
            DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, L"MS Shell Dlg 2");

        RECT rect;
        GetClientRect(&rect);
        _static.Create(m_hWnd, rect, NULL, WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE, WS_EX_TRANSPARENT);
        _static.SetWindowText(L"Test");
        _static.SetFont(_staticFont);
        
        SetTimer(NULL, 1000, NULL);

        UpdateTime();

        return 0;
    }

    void OnTimer(UINT_PTR nIDEvent)
    {
        UpdateTime();
    }

    void UpdateTime()
    {
        SYSTEMTIME time;
        GetLocalTime(&time);

        LPWSTR format = L"HH:mm:ss";

        int size = GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, LOCALE_USE_CP_ACP, &time, format, NULL, 0);
        auto text = std::unique_ptr<wchar_t[]>(new wchar_t[size]);
        GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, LOCALE_USE_CP_ACP, &time, format, text.get(), size);

        Invalidate();
        _static.SetWindowText(text.get());
    }

    HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic)
    {
        if(wndStatic.m_hWnd == _static.m_hWnd)
        {
            dc.SetTextColor(RGB(227, 78, 78));
            dc.SetBkMode(TRANSPARENT);
        }

        return reinterpret_cast<HBRUSH>(GetStockObject(NULL_BRUSH));
    }

    BOOL OnBackgroundPaint(CDCHandle dc)
    {
        RECT rect;
        GetClientRect(&rect);

        dc.FillRect(&rect, _backgroundBrush);

        return TRUE;
    }

    void OnClose()
    {
        DestroyWindow();
    }

    void OnDestroy()
    {
        PostQuitMessage(0);
    }

public:
    DECLARE_WND_CLASS(NULL)

    MainForm()
    {
        RECT rect = { 0, 0, 400, 150 };

        if(Create(NULL, rect, L"Czas") == NULL)
            throw std::exception();

        CenterWindow();
    }
};

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    std::unique_ptr<MainForm> form;

    try
    {
        form = std::unique_ptr<MainForm>(new MainForm);
        form->ShowWindow(nCmdShow);
    }
    catch(std::exception&)
    {
        MessageBox(NULL, L"Błąd", L"Błąd", MB_ICONERROR);
        
        return 1;
    }

    MSG message;
    while(GetMessage(&message, NULL, 0, 0) > 0)
    {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }

    return message.wParam;
}

user image

0
Rev napisał(a)

auto text = std::unique_ptr<wchar_t[]>(new wchar_t[size]);

Kwestia gustu, ale można użyć też smart-pointera z ATL:

CHeapPtr<wchar_t> text(new wchar_t[size]);

albo

CHeapPtr<wchar_t> text;
text.Allocate(size);
0

Zrobiłem tak (KISS), jedyny problem, że rozmiar czcionki zmienia się po wystąpieniu komunikatu WM_TIMER (czyli po ok. 1 sekundzie), wstawienie SendMessage do WM_CREATE nic nie zmienia.

#include <time.h>
#include <stdio.h>
#include <windows.h>


//===================================================
//GLOBAL VARIABLE
//===================================================
HINSTANCE main_hinst;
MSG main_msg;
HWND main_hwnd;
HWND main_editbox;

char s_time[9];
HFONT hFont;
//===================================================

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, NULL, "hh':'mm':'ss", s_time, 9);
    switch (message)
    {
        case WM_CREATE:
        {
            SetTimer( hwnd, 1, 1000, NULL );
            hFont = CreateFont(30,0,0,0,0,0,0,0,EASTEUROPE_CHARSET,0,0,0,0,"Verdana");
            break;
        }
        case WM_TIMER:
        {
            SendMessage(main_editbox, WM_SETFONT, WPARAM (hFont), TRUE);
            SendMessage(main_editbox, WM_SETTEXT, 9, (LPARAM)s_time);
            break;
        }
        case WM_DESTROY:
        {
            DeleteObject(hFont);
            PostQuitMessage(0);
            return 0;
        }
    }
    return DefWindowProc (hwnd, message, wParam, lParam);
}


int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASS main_wc;

    const char *AppName = "Manor Timer";
    memset(&main_wc,0,sizeof(WNDCLASS));
    main_wc.style         = CS_HREDRAW | CS_VREDRAW;
    main_wc.lpfnWndProc   = WndProc;
    main_wc.hInstance     = main_hinst;
    main_wc.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    main_wc.hCursor       = LoadCursor (NULL, IDC_ARROW);
    main_wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    main_wc.lpszMenuName  = NULL;
    main_wc.lpszClassName = AppName;

    RegisterClass (&main_wc);

    main_hwnd = CreateWindow (AppName,            // window class name
                              TEXT ("Manor Timer"),         // window caption
                              WS_SYSMENU,//WS_BORDER|WS_POPUP,      // window style
                              GetSystemMetrics(SM_CXSCREEN)- 200,//CW_USEDEFAULT,   // initial x position
                              200,                          // initial y position
                              145,                          // initial x size
                              70,                           // initial y size
                              HWND_DESKTOP,        // parent window handle
                              NULL,                       // window menu handle
                              main_hinst,               // program instance handle
                              NULL);                     // creation parameters

    if(main_hwnd == NULL)
    {
        MessageBox (NULL , "Failed to create window", "Manor Timer", MB_ICONERROR);
        return 0;
    }
    main_editbox = CreateWindow("EDIT", s_time, WS_CHILD|WS_VISIBLE, 5, 5, 135, 55, main_hwnd, 0, main_hinst, 0);

    ShowWindow(main_hwnd, SW_SHOW);
    UpdateWindow(main_hwnd);

    while(GetMessage(&main_msg, NULL, 0, 0))
    {
        TranslateMessage (&main_msg);
        DispatchMessage (&main_msg);
    }
    return main_msg.wParam ;
}
0

kilka błędów:

• SendMessage do editboksa w WM_CREATE oczywiście nie działa, bo EDIT jeszcze nie istnieje.
• Niepotrzebne zmienne globalne, zwłaszcza main_msg używana tylko pod koniec funkcji WinMain.
• Nie wolno jako parenta okna dawać HWND_DESKTOP. Jeśli okno ma być głównym, dajemy NULL.
• Zmienna main_hinst jest u ciebie zawsze równa 0. Wywaliłem, zamiast niej użyłem hInstance.
• Dlaczego w ogóle czas wyświetlasz w Edicie? Od takich rzeczy jest STATIC albo własne rysowanie (TextOut) w WM_PAINT.
• GetTimeFormat przy każdym wywołaniu WndProc; po co?
• DefWindowProc przy każdym wywołaniu WndProc; powinno być w zasadzie tylko przy default:.
• Główne okno programu przy ShowWindow powinno użyć parametru nCmdShow a nie na sztywno SW_SHOW.

#include <time.h>
#include <stdio.h>
#include <windows.h>
 
//===================================================
//GLOBAL VARIABLES
//===================================================
HWND main_editbox;
HWND main_hwnd;
HFONT hFont;
//===================================================

void updateClock()
{
    char s_time[9];
    GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, NULL, "hh':'mm':'ss", s_time, 9);
    SendMessage(main_editbox, WM_SETTEXT, 9, (LPARAM)s_time);
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_CREATE:
        {
            hFont = CreateFont(30,0,0,0,0,0,0,0,EASTEUROPE_CHARSET,0,0,0,0,"Verdana");
            break;
        }
        case WM_SHOWWINDOW:
        {
            if (wParam)
            {
                SendMessage(main_editbox, WM_SETFONT, (WPARAM)hFont, TRUE);
                updateClock();
                SetTimer( hwnd, 1, 1000, NULL );
            }
        }
        case WM_TIMER:
        {
            updateClock();
            break;
        }
        case WM_DESTROY:
        {
            DeleteObject(hFont);
            PostQuitMessage(0);
            break;
        }
        default:
            return DefWindowProc (hwnd, message, wParam, lParam);
    }
    return 0;
}
 
 
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASS main_wc;
 
    const char *AppName = "Manor Timer";
    memset(&main_wc,0,sizeof(WNDCLASS));
    main_wc.style         = CS_HREDRAW | CS_VREDRAW;
    main_wc.lpfnWndProc   = WndProc;
    main_wc.hInstance     = hInstance;
    main_wc.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    main_wc.hCursor       = LoadCursor (NULL, IDC_ARROW);
    main_wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    main_wc.lpszMenuName  = NULL;
    main_wc.lpszClassName = AppName;
 
    RegisterClass (&main_wc);

    main_hwnd = CreateWindow (AppName,            // window class name
                              TEXT ("Manor Timer"),         // window caption
                              WS_SYSMENU,//WS_BORDER|WS_POPUP,      // window style
                              GetSystemMetrics(SM_CXSCREEN)- 200,//CW_USEDEFAULT,   // initial x position
                              200,                          // initial y position
                              145,                          // initial x size
                              70,                           // initial y size
                              0,                        // parent window handle
                              NULL,                       // window menu handle
                              hInstance,               // program instance handle
                              NULL);                     // creation parameters
 
    if(main_hwnd == NULL)
    {
        MessageBox (NULL , "Failed to create window", "Manor Timer", MB_ICONERROR);
        return 0;
    }
    main_editbox = CreateWindow("EDIT", NULL, WS_CHILD|WS_VISIBLE, 5, 5, 135, 55, main_hwnd, 0, hInstance, 0);
 
    ShowWindow(main_hwnd, nCmdShow);
    UpdateWindow(main_hwnd);
 
    MSG main_msg;
    while(GetMessage(&main_msg, NULL, 0, 0))
    {
        TranslateMessage (&main_msg);
        DispatchMessage (&main_msg);
    }
    return main_msg.wParam ;
}

edit: CreateFont przeniesione z powrotem do WM_CREATE by uniknąć wycieku.

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