구리의 창고

QT Programming - Frameless 윈도우에서 메뉴와 타이틀바, Vista7&XP 본문

QT

QT Programming - Frameless 윈도우에서 메뉴와 타이틀바, Vista7&XP

구리z 2012. 1. 10. 16:19
프로그램을 만드는데 QMainWindow를 상속 받아 투명처리와 테두리를 없애고 타이틀바와 메뉴바를 붙이고 있다.

* 투명처리와 테두리를 없애는 코드

    setAttribute(Qt::WA_TranslucentBackground, true);
setWindowFlags(Qt::FramelessWindowHint); 


일단 QMainWindow의 기본적인 레이아웃은 아래와 같다.

해당 레이아웃은  (src/gui/widgets/qmainwindowlayout.cpp) 에 정의 돼 있다.

 
저 레이아웃에 정의 돼 있는 MenuBar 위치를 그대로 쓰게되면 타이틀 바를 넣을 수가 없으므로 기본적으로 제공하는 QLayout::setMenuBar() 함수는 쓸 수가 없다.

QWidget 위에 타이틀바를 먼저 넣고 메뉴바를 넣고, Central Widget을 설정해줘야한다.

그래서 첫 번째 시도로 나머지는 다 버리고 Central Widget 안에 다 넣기로 했다.

*TitleBar 와 MainWidget은 따로 구현한 커스톰 클래스이다. 

QWidget* centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
QVBoxLayout* vBox = new QVBoxLayout(centralWidget);
vBox->setSpacing(0);
vBox->setContentsMargins(0, 0, 0, 0);
TitleBar* titleBar = new TitleBar;
vBox->addWidget(titlebar);
QMenuBar* menuBar = new QMenuBar;
vBox->addWidget(menuBar);
MainWidget* mainWidget = new MainWidget;
vBox->addWidget(mainWidget);


윈도우7과 비스타에서는 제대로 작동했지만, XP에서 이상하게 출력됐다. 


위 사진이 XP, 아래 사진이 7 인데, XP에서는 빈 공간이 제대로 출력되지 않음을 볼 수 있다.

오만 별짓을 다해도 안되길래 QWindowsXPStyle과 QWindowsVistaStyle을 살펴보기로했다.

main 함수에서 QApplication::style() 을 찍어보면 각 OS에서 위에 말한 Style들을 사용하고 있음을 알 수 있다.

drawControl을 오버로딩받아 ControlElement가 CE_MenuBarEmptyArea와 CE_MenuBarItem 인 경우만 다시 그려봤다.

XP에서 잘돌아간다 굿!! 하지만 7에서는 제대로 표시가안된다. 메뉴가 밖으로 삐져나온다.

그래서 다른 방법을 생각해봤는데, TitleBar와 MenuBar를 centralWidget에 넣지않고 마지막에생성하면

CentralWidget보다 TitleBar와 MenuBar가 위로 올라올 것이다.

그리고 TitleBar와 MenuBar의 높이는 고정이므로 윗 부분의 빈공간에 빈 Widget을 하나 넣어주면 될 것 같았다.

코드는 아래와 같다.

	QWidget* centralWidget = new QWidget(this);
	
	setCentralWidget(centralWidget);

	vbox = new QVBoxLayout(centralWidget);
	vbox->setSpacing(0);
	vbox->setContentsMargins(0, 0, 0, 0);

	emptyHeight = 45;

	emptyWidget = new QWidget;
	emptyWidget->setMinimumHeight(emptyHeight);
	emptyWidget->setMaximumHeight(emptyHeight);
	emptyWidget->setGeometry(0, 0, width(), emptyHeight);
	
	addWidget(emptyWidget);
	
	titleBar = createTitleBar();
	menuBar = createMenuBar();


해결 방법을 정리하면 아래와 같다.

1. QMainWindow::centralWidget에 들어갈 widget을 만든다.
2. centralWidget위에 QVBoxLayout을 생성한다.
3. 생성한 타이틀바와 메뉴바의 높이를 합한 후 계산해 빈 Widget을 만들어준다. (소스코드의 emptyWidget)
4. 2번과정에서 생성한  QVBoxLayout에 addWidget을 해준다. - centralWidget 준비 끝
5. this(QMainWindow)위에 타이틀바와 메뉴바를 각각 setGeometry 함수를 이용해 위치를 지정한다.

* 주의 : 5번을 먼저해주면 위젯이 밑으로 내려가 아무 이벤트도 발생하지 않는다.
Comments