12-26-2025, 11:14 PM
This is a utility that allows you to select a date from a calendar. The function returns the selected date as a string.
program need pdate.h file.
pdate.h:
pdate.bas:
program need pdate.h file.
pdate.h:
Code: (Select All)
#ifndef QB64PE_PICKDATE_H
#define QB64PE_PICKDATE_H
#ifndef _WIN32
#error "pickdate.h je jen pro Windows."
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
// kvůli některým definicím common controls
#ifndef _WIN32_IE
#define _WIN32_IE 0x0501
#endif
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#define QB64_PICKDATE_CLASSA "QB64PE_PickDateWindow"
#define IDC_QB64_MONTHCAL 1010
#define IDC_QB64_OK 1
#define IDC_QB64_CANCEL 2
typedef BOOL (WINAPI *PFN_InitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
static void qb64_pickdate_init_comctl_dateclasses(void) {
// Bezpečně: dynamicky natáhnout comctl32 a zavolat InitCommonControlsEx (bez linkování comctl32)
HMODULE hComctl = LoadLibraryA("comctl32.dll");
if (!hComctl) return;
PFN_InitCommonControlsEx pInit =
(PFN_InitCommonControlsEx)GetProcAddress(hComctl, "InitCommonControlsEx");
if (!pInit) return;
INITCOMMONCONTROLSEX icc;
ZeroMemory(&icc, sizeof(icc));
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_DATE_CLASSES;
pInit(&icc);
}
typedef struct qb64_pickdate_ctx_s {
HWND hwnd;
HWND hCal;
SYSTEMTIME stInit;
SYSTEMTIME stSel;
int hasInit;
int ok;
} qb64_pickdate_ctx;
static void qb64_pickdate_center_window(HWND hwnd) {
RECT rc;
GetWindowRect(hwnd, &rc);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
int sw = GetSystemMetrics(SM_CXSCREEN);
int sh = GetSystemMetrics(SM_CYSCREEN);
int x = (sw - w) / 2;
int y = (sh - h) / 2;
SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
static void qb64_pickdate_layout(HWND hwnd, qb64_pickdate_ctx* ctx) {
// Zjisti minimální potřebný rozměr MonthCal
RECT r = {0,0,0,0};
SendMessageA(ctx->hCal, MCM_GETMINREQRECT, 0, (LPARAM)&r);
int calW = (r.right - r.left);
int calH = (r.bottom - r.top);
if (calW <= 0) calW = 220;
if (calH <= 0) calH = 160;
const int pad = 10;
const int btnW = 90;
const int btnH = 26;
const int gap = 10;
int clientW = calW + pad * 2;
int minBtnRow = (btnW * 2 + gap) + pad * 2;
if (clientW < minBtnRow) clientW = minBtnRow;
int calX = pad;
int calY = pad;
int btnY = calY + calH + pad;
int okX = (clientW / 2) - gap/2 - btnW;
int cancelX = (clientW / 2) + gap/2;
MoveWindow(ctx->hCal, calX, calY, calW, calH, TRUE);
HWND hOk = GetDlgItem(hwnd, IDC_QB64_OK);
HWND hCancel = GetDlgItem(hwnd, IDC_QB64_CANCEL);
MoveWindow(hOk, okX, btnY, btnW, btnH, TRUE);
MoveWindow(hCancel, cancelX, btnY, btnW, btnH, TRUE);
int clientH = btnY + btnH + pad;
// Přepočet na velikost okna podle stylu
RECT wr = {0, 0, clientW, clientH};
DWORD style = (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE);
DWORD exStyle = (DWORD)GetWindowLongPtr(hwnd, GWL_EXSTYLE);
AdjustWindowRectEx(&wr, style, FALSE, exStyle);
int winW = wr.right - wr.left;
int winH = wr.bottom - wr.top;
SetWindowPos(hwnd, NULL, 0, 0, winW, winH, SWP_NOZORDER | SWP_NOMOVE);
qb64_pickdate_center_window(hwnd);
}
static LRESULT CALLBACK qb64_pickdate_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
qb64_pickdate_ctx* ctx = (qb64_pickdate_ctx*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
switch (msg) {
case WM_NCCREATE: {
CREATESTRUCTA* cs = (CREATESTRUCTA*)lParam;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams);
return TRUE;
}
case WM_CREATE: {
ctx = (qb64_pickdate_ctx*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
ctx->hCal = CreateWindowExA(
0,
MONTHCAL_CLASSA, "",
WS_CHILD | WS_VISIBLE | WS_BORDER,
10, 10, 220, 160,
hwnd, (HMENU)(INT_PTR)IDC_QB64_MONTHCAL,
GetModuleHandleA(NULL), NULL
);
CreateWindowExA(
0, "BUTTON", "OK",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
10, 180, 90, 26,
hwnd, (HMENU)(INT_PTR)IDC_QB64_OK,
GetModuleHandleA(NULL), NULL
);
CreateWindowExA(
0, "BUTTON", "Storno",
WS_CHILD | WS_VISIBLE,
110, 180, 90, 26,
hwnd, (HMENU)(INT_PTR)IDC_QB64_CANCEL,
GetModuleHandleA(NULL), NULL
);
if (ctx->hasInit) {
SendMessageA(ctx->hCal, MCM_SETCURSEL, 0, (LPARAM)&ctx->stInit);
}
qb64_pickdate_layout(hwnd, ctx);
return 0;
}
case WM_COMMAND: {
int id = LOWORD(wParam);
if (id == IDC_QB64_OK) {
SYSTEMTIME st;
ZeroMemory(&st, sizeof(st));
SendMessageA(ctx->hCal, MCM_GETCURSEL, 0, (LPARAM)&st);
ctx->stSel = st;
ctx->ok = 1;
DestroyWindow(hwnd);
return 0;
}
if (id == IDC_QB64_CANCEL) {
ctx->ok = 0;
DestroyWindow(hwnd);
return 0;
}
return 0;
}
case WM_CLOSE:
if (ctx) ctx->ok = 0;
DestroyWindow(hwnd);
return 0;
}
return DefWindowProcA(hwnd, msg, wParam, lParam);
}
static ATOM qb64_pickdate_register_class(void) {
static ATOM atom = 0;
if (atom) return atom;
WNDCLASSEXA wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = qb64_pickdate_wndproc;
wc.hInstance = GetModuleHandleA(NULL);
wc.lpszClassName = QB64_PICKDATE_CLASSA;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
atom = RegisterClassExA(&wc);
return atom;
}
// Exportovaná funkce pro QB64PE:
// outISO = buffer (STRING proměnná), outISOBytes = velikost bufferu, initialISO = "YYYY-MM-DD\0" nebo ""\0
// Return: 1=OK, 0=storno/chyba
int qb64_pickdate(char* outISO, int outISOBytes, const char* initialISO) {
if (!outISO || outISOBytes <= 0) return 0;
outISO[0] = 0;
qb64_pickdate_init_comctl_dateclasses();
if (!qb64_pickdate_register_class()) return 0;
qb64_pickdate_ctx ctx;
ZeroMemory(&ctx, sizeof(ctx));
// default: dnešní datum
GetLocalTime(&ctx.stInit);
ctx.hasInit = 1;
// pokud je initialISO zadáno jako YYYY-MM-DD, použij ho
if (initialISO && initialISO[0]) {
int y=0, m=0, d=0;
if (sscanf(initialISO, "%d-%d-%d", &y, &m, &d) == 3) {
if (y >= 1601 && m >= 1 && m <= 12 && d >= 1 && d <= 31) {
ctx.stInit.wYear = (WORD)y;
ctx.stInit.wMonth = (WORD)m;
ctx.stInit.wDay = (WORD)d;
}
}
}
HWND hwnd = CreateWindowExA(
WS_EX_DLGMODALFRAME,
QB64_PICKDATE_CLASSA,
"Vyber datum",
WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 260,
NULL, NULL,
GetModuleHandleA(NULL),
&ctx
);
if (!hwnd) return 0;
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
// modal-ish smyčka: pumpuje zprávy, dokud okno existuje
MSG msg;
while (IsWindow(hwnd) && GetMessageA(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessageA(&msg);
}
if (!ctx.ok) return 0;
// Zapiš výsledek
int n = snprintf(outISO, (size_t)outISOBytes, "%04u-%02u-%02u",
(unsigned)ctx.stSel.wYear, (unsigned)ctx.stSel.wMonth, (unsigned)ctx.stSel.wDay);
// pojistka NUL
outISO[outISOBytes - 1] = 0;
return (n > 0) ? 1 : 0;
}
#endif // QB64PE_PICKDATE_HCode: (Select All)
$Console
Declare CustomType Library "pdate"
Function PickDate% Alias qb64_pickdate (outISO As String, ByVal outISOBytes As Long, initialISO As String)
End Declare
Dim out$, init$
out$ = Space$(32) ' buffer for "YYYY-MM-DD" + NUL
init$ = ""
ok% = PickDate(out$, Len(out$), init$ + Chr$(0))
If ok% Then
p = InStr(out$, Chr$(0))
If p > 0 Then out$ = Left$(out$, p - 1)
Print "Date selected: "; out$
Else
Print "Storno or fail."
End If
Sleep
End

