Fenster Position und Grösse

Thomasio

Erfahrenes Mitglied
Ich habe ein Problem vom Typ kann gar nicht sein, vermutlich bin ich einfach nur zu blind für einen ganz simplen Fehler.

Zuerst erstelle ich ein MainWindow

Code:
hwnd = CreateWindow(
                     MainClassName.c_str(),
                     MainWindowName.c_str(),
                     WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|CS_DROPSHADOW,
                     0,0,736,488,
                     HWND_DESKTOP,0,hinstance,0
                   );

Dann im WM_CREATE 2 weitere

Code:
case WM_CREATE:

MyChild1                 = CreateWindow(
                                            "Child1Name","",
                                            WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_CLIPCHILDREN|CS_DROPSHADOW,
                                            0,0,0,0,
                                            hWnd,0,hinstance,0
                                          );
MyChild2                 = CreateWindow(
                                            "Child2Name","",
                                            WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_CLIPCHILDREN|CS_DROPSHADOW,
                                            0,0,0,0,
                                            hWnd,0,hinstance,0
                                          );

break;

Das Ganze erstmal völlig leer, nur der standard Windows-Rahmen drumrum.
Jetzt will ich Position und Grösse der Child Fenster setzen.

Code:
MoveWindow(MyChild1,0,0,366,388,1);
MoveWindow(MyChild2,0,0,501,398,1);

Das Ergebnis kann ich via Screenshot nachmessen.
Child1 ist genau wie gewünscht 366x388px gross.
Child2 ist 511x408, also 10 breiter und 10 höher als angegeben.

Was soll das?

Edit / Update:

Jetzt habe ich zumindest rausgefunden woran es liegt.
10px breiter und höher wird ein Child wenn das MainWindow im Style WS_OVERLAPPEDWINDOW hat, das Child aber nur WS_OVERLAPPED.
Dass Child1 trotzdem richtig war lag an was anderem.
Bleibt noch die Frage: Wieso macht Windows das Child 10px grösser, nur weil der Style verschieden ist?
 
Zuletzt bearbeitet:
Das macht normalerweise Windows nicht.
Wie sehen deine Klassendeklarationen und WndProcs dazu aus?

Übrigens, CS_DROPSHADOW ist ein Class Style, kein Window Style, der hat da nichts zu suchen.
 
Das ist alles (noch) leer, ich will ja erstmal nur die Position setzen.

Code:
WNDCLASSEX wc;

wc.hInstance     = hinstance;
wc.lpszClassName = MainClassName.c_str();
wc.lpfnWndProc   = MainWindow;
wc.style         = 0;
wc.cbSize        = sizeof(wc);
wc.hIcon         = 0;
wc.hIconSm       = (HICON)LoadImage(GetModuleHandle(0),
                   MAKEINTRESOURCE(ID_icon_main),IMAGE_ICON,16,16,0);
wc.hCursor       = LoadCursor(0,IDC_ARROW);
wc.lpszMenuName  = 0;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hbrBackground = 0;
RegisterClassEx(&wc);

wc.lpszClassName = "Child1Name";
wc.lpfnWndProc   = MyChild1Window;
RegisterClassEx (&wc);

wc.lpszClassName = "Child2Name";
wc.lpfnWndProc   = MyChild2Window;
RegisterClassEx (&wc);

Die WndProcs sind völlig leer.

Code:
LRESULT CALLBACK MainWindow(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return DefWindowProc(hWnd,msg,wParam,lParam);
}

LRESULT CALLBACK MyChild1Window(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return DefWindowProc(hWnd,msg,wParam,lParam);
}

LRESULT CALLBACK MyChild2Window(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return DefWindowProc(hWnd,msg,wParam,lParam);
}
 
Da geht noch was anderes vor sich, ich kann das so nicht nachstellen. Poste mal bitte dein komplettes Projekt.
 
Da steht nichts weiter drin, ich habe es zum Testen auf dieses Minimum reduziert.
Aber bitte, hier das Ganze in komplett

Resource.rc
Code:
#include "_Resource.h"

ID_icon_main ICON "icon_main.ico"

Resource.h
Code:
#ifndef RESOURCE_H
#define RESOURCE_H

#define WINVER 0x0500
#define _WIN32_IE 0x0501
#define UNICODE
#define _UNICODE

#ifndef RC_INVOKED

#include <windows.h>
#include <sstream>
#include <vector>
#include <algorithm>
#include <time.h>
#include <commctrl.h>
#include <shlobj.h>

#endif

#ifndef CS_DROPSHADOW
#define CS_DROPSHADOW 0x00020000
#endif

#define ID_icon_main 1

#endif

Main.cpp
Code:
#include "_Resource.h"

using namespace std;

wstring MainClassName = L"MyWindow";
wstring MainWindowName = L"Test";

HINSTANCE hinstance;

HWND hwnd,MyChild1,MyChild2;

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR szCmdLine,int nCmdShow)
{

hinstance = hInstance;

WNDCLASSEX wc;
 
wc.hInstance     = hinstance;
wc.lpszClassName = MainClassName.c_str();
wc.lpfnWndProc   = MainWindow;
wc.style         = 0;
wc.cbSize        = sizeof(wc);
wc.hIcon         = 0;
wc.hIconSm       = (HICON)LoadImage(GetModuleHandle(0),
                   MAKEINTRESOURCE(ID_icon_main),IMAGE_ICON,16,16,0);
wc.hCursor       = LoadCursor(0,IDC_ARROW);
wc.lpszMenuName  = 0;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hbrBackground = 0;
RegisterClassEx(&wc);
 
wc.lpszClassName = L"Child1Name";
wc.lpfnWndProc   = MyChild1Window;
RegisterClassEx (&wc);
 
wc.lpszClassName = L"Child2Name";
wc.lpfnWndProc   = MyChild2Window;
RegisterClassEx (&wc);

hwnd = CreateWindow(
                     MainClassName.c_str(),
                     MainWindowName.c_str(),
                     WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|CS_DROPSHADOW,
                     0,0,736,488,
                     HWND_DESKTOP,0,hinstance,0
                   );

MSG msg;

while(GetMessage(&msg,0,0,0) > 0)
     {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
     }

return msg.wParam;

}


LRESULT CALLBACK MainWindow(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{

case WM_CREATE:
 
MyChild1                 = CreateWindow(
                                            L"Child1Name",L"",
                                            WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_CLIPCHILDREN|CS_DROPSHADOW|WS_VISIBLE,
                                            0,0,0,0,
                                            hWnd,0,hinstance,0
                                          );
MyChild2                 = CreateWindow(
                                            L"Child2Name",L"",
                                            WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_CLIPCHILDREN|CS_DROPSHADOW|WS_VISIBLE,
                                            0,0,0,0,
                                            hWnd,0,hinstance,0
                                          );
 

MoveWindow(MyChild1,0,0,366,388,1);
MoveWindow(MyChild2,0,0,501,398,1);

break;

}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
 
LRESULT CALLBACK MyChild1Window(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return DefWindowProc(hWnd,msg,wParam,lParam);
}
 
LRESULT CALLBACK MyChild2Window(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return DefWindowProc(hWnd,msg,wParam,lParam);
}

Den falschen DROPSHADOW habe ich noch dringelassen, ich weiss aber jetzt wie es sein sollte.
 
Zuletzt bearbeitet:
Ich kann das hier nicht nachvollziehen (Windows 7 mit Aero). GetWindowRect gibt die erwarteten Werte aus. Nachmessen auf Screenshots erweist sich als etwas schwierig wegen des Aero-Rahmens, aber in Relation gesehen haben beide Fenster die korrekte Größe.

Grüße,
Matthias
 
Stimmt, GetWindowRect() gibt die gewünschten Werte aus, aber GetClientRect() nicht, bzw. die stimmen nicht überein.
Bei mir (Win7 Aero) ist z.B. der Rahmen 8px breit, links plus rechts also 16px.
Also sollte GetClientRect() eine Breite von 350 bringen.

Code:
...

MoveWindow(MyChild1,0,0,366,388,1);

RECT rect1,rect2;
GetWindowRect(MyChild1,&rect1);
GetClientRect(MyChild1,&rect2);

if(rect1.right - rect1.left == 366)
{
// Gesamtbreite correct
}
else
{
// error
}
if(rect2.right == 350)
{
// Clientbreite correct
}
else if(rect2.right == 360)
{
// Client 10 zu breit
}
else
{
// Client ganz falsch
}

Ich bekomme immer "Gesamtbreite korrekt" und "Client 10 zu breit", was offensichtlich nicht sein kann.
Im Screenshot nachgemessen hat das Fenster dann 376 Breite, obwohl GetWindowRect() nur 366 ausgibt.

Edit:
Was ich ganz merkwürdig finde, bzw. was fast bestätigt, dass mein Code keinen Fehler hat ist die Tatsache, dass dieses Verhalten nicht auftritt, wenn ich mache:

Code:
hwnd = CreateWindow(
                     MainClassName.c_str(),
                     MainWindowName.c_str(),
                     WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_CLIPCHILDREN|CS_DROPSHADOW,
                     0,0,736,488,
                     HWND_DESKTOP,0,hinstance,0
                   );
 
Zuletzt bearbeitet:
Stimmt, GetWindowRect() gibt die gewünschten Werte aus, aber GetClientRect() nicht, bzw. die stimmen nicht überein.
Bei mir (Win7 Aero) ist z.B. der Rahmen 8px breit, links plus rechts also 16px.
Also sollte GetClientRect() eine Breite von 350 bringen.
Deine falsche Annahme ist, dass GetWindowRect() immer die sichtbare Größe des Fensters auf dem Bildschirm zurückliefert. Das ist mit Aero aber nicht der Fall, da die Fensterränder nur teilweise zum WindowRect zählen. Siehe z.B. hier: http://social.msdn.microsoft.com/Fo.../thread/6c1c67a9-5548-4e9b-989f-c7dbac0b1375/

Grüße,
Matthias
 
Zurück