페이지

Include Lists

레이블이 QT인 게시물을 표시합니다. 모든 게시물 표시
레이블이 QT인 게시물을 표시합니다. 모든 게시물 표시

2017년 8월 2일 수요일

선택할 수 없는 영역이 있는 TableWidget 만들기




 What
   - 선택할 수 없는 영역의 있는 TableWidget

 Usage
   - QTableWidget을 재정의하여 개발



   

  
구현 해야 할 UI는 리스트 위젯이다. 그런데, 그림에서 보면 일단 버튼이 보인다.
그럼 리스트 위젯이 아닌, 리스트 위젯과 유사한 QTableWidget을 사용하여 구현한다.

  1. 테이블의 row hover
  2. 윈도우 크기에 따른 테이블 row의 삽입 / 삭제 기능
  3. 실제 클릭할 row는 5개 이고, 그 외의 row에 대해서는 어떠한 이벤트도 발생하지 않는다.


[1] 테이블의 Row Hover 기능
  • 기본적인 Table 위젯의 기능 외에 추가적으로 구현 해야하는 기능은 위와 같다. Row열에 대한 Hover 기능을 어떻게 구현해야 할 것인가? QTableWidget에는 Item에 대한 Hover 기능은 있지만, Item의 Row에 대한 hover 기능은 없는 듯 하다. (Selection Row는 있는데..) 그래서 직접 구현해야 한다. ㅠ_ㅠ
호버 이벤트가 발생되는 signal을 캡쳐하여, Row에 대한 hover 이벤트가 발생되도록 한다.

  • void itemEntered(QTableWidgetItem * item)  라는 signal 에 대해서 row hover 이벤트가 발생되도록 한다.
  • 버튼은 tableitem의 cellwidget으로 구현해야 한다. 그렇기 때문에, 버튼에 대해서는 itemEnter이벤트가 발생되지 않으므로,
해당 버튼의 enterEvent를 통해서 hover이벤트를 전달한다.


[2] 윈도우 크기에 따른 테이블 row의 삽입 / 삭제 기능
   - 위 그림 처럼 보이기 위해선 실제 row를 삽입해야만 위 처럼 보일 수 있다. Table Widget의 ResizeEvent를 override 하여 크기에
     따라서 row를 삽입 / 삭제 할지를 판단해야 한다.


[3] 실제 클릭할 row는 5개 이고, 그 외의 row에 대해서는 어떠한 이벤트도 발생하지 않는다.
  • 그림처럼 row가 보일려면 실제 row를 삽입해야만 하고, 존재하는 row이므로, 선택은 반드시 되게 되어 있다. 그럼 이것을 어떻게 우회 할 수 있을까?! 처음에는 선택시, 해당 row > 5 는 조건일 때, 해당 이벤트를 무시하도록 했으나, 언제나 그렇듯 한방에 되지는 않는다. 그렇다면? QTableWidget의 선택모드를 강제로 비활성화 하고, MousePressEvent는 HoverEvent가 발생한 뒤 발생하는 것이므로, Hover시 현재 row에 대해서 선택 가능 상태를 판단하고, MousePressEvent에서 hover된 row를 선택 하도록 한다.


[4] 삭제 기능시 cellwidget의 정의된 아이템이 visible이 true가 되는 상태.
  • Hover시에만 삭제 버튼이 보여서 클릭이 가능하다. 처음 시도한 방법은 cellWidget의 visible 상태를 변경하는 것이였다.
그러나, removeRow만 하면, cellWidget이 살아나는 것이다. 심지어 removeRow 후에 다시 상태를 변경해도 변경이 되지 않았다. 결국 setVisible 상태 변경으로 위 문제를 해결하기는 힘들었다. 과연 방법은 무엇일까?! TableWidget을 Qwidget으로 완전 새로이 만들 수도 있지만, 결국 난 상태에 따라서 버튼의 visible 상태만 변경하면 되므로, styleSheet 상태를 변경하는 것을 선택하였다.



기본 UI


  • 마우스 우클릭시 row 에 대해 삽입/삭제가 가능하다.
  • 삽입은 순차적으로 되며, 삭제는 현재 row에 대해서 삭제한다.

 

  • 0번째 row는 선택 상태이며,
  • 2번쨰 row는 호버 상태이다. 호버 상태에서만  x 버튼이 활성화 된다.
  • 3번 이후 row에 대해서는 선택할 수 없다.

 

  
  • Resize 커졌을 때와 resize 작아졌을 때의 모습이다.
  • 미세조정이 필요하나, 실제 개발버전에서나 미세조정하여 적용하고, 위 처럼 기능 구현을 하면 된다.


[*] "선택할 수 없게 만든 다음, 강제로 내가 선택된거 처럼 만든다."
     개발 기간 5일, 위 기능을 개발하면서 refresh 되는 기분을 느낄 수 있었다.
     1-2틀 고민하면서 해결하지 못했던 부분이 선택할 수 없는 영역에 대해서 선택하지 못하도록 하는것에 대한 방법을 찾는 것이였다.
     위 기능에 대해 Devman에게 조언을 구했고, devman이 해당 기능에 대해서 위와 같이 마무리 해줬다.
     만일 나였다면, 어떻게 했을까 생각을 해본다면, 안된다고 포기하고 QTableWidget을 사용하지 않고, 해당 기능처럼
     동작하는 QWidget과 QLayout들을 사용하여 직접 구현했을 것이라고 생각이 들었다.
     위같은 방법으로도 할 수 있다는 것에 기분전환이 되었고, 도움을 준 devman에게 고맙다. ㅋㅋㅋㅋ

Qt Widget의 그림자 효과주기






 What
   - Qt 위젯의 그림자 효과주기






위 같은 하나의 위젯의 테두리에 그림자 효과를 만들어야 하는 미션이 떨어졌다.

디자이너는 이것을 OutGlow라고 하였다.

그래서 검색을 하던 중, Qt에 QGraphicsDropShadowEffect 라는 class에서 비슷한 기능을 제공하고 있었다.

하지만 우리의 디자인은 Qt에서 제공하는 기본 기능으로만 구현 되는것을 요구하진 않는다.

좀더 큰 radius와 퍼짐이 좀 더 큰 효과를 원했다.

그래서 검색을 하던 중, 역시나 StackOverflow에는 나보다 먼저 고민을 한 사람이 있었다.
https://stackoverflow.com/questions/23718827/qt-shadow-around-window 의 글을 참조하여 적용해 보았다.





왼쪽은 QGraphicsDropShadowEffect 를 적용한 Widget이며,
오른쪽은 ShadowEffect라는 Class를 통해 적용된  Widget이다.





Position 은 Shadow Effect의 위치를 나타내며, 0.0 일때, 정중앙을 기준으로 shadow 효과가 나타난다.
Length는 shadow의 크기를 나타내며, normal effect 에는 적용이 안된다.

Radius는 0일때 사각형이며, 커질 수록 곡률이 생긴다.

Binary  : https://drive.google.com/open?id=0ByvWiBJz6HrFQjZaWEdyY2lzejQ
Source : https://github.com/holograming/QtDevZone/tree/master/Src/OutGlow

2017년 8월 1일 화요일

Qt Layout 과 WIdget의 크기 변화에 따른 동작








 What
   - Qt를 사용한 Layout 정렬 및 Resizing 동작 파악

 Why
   - Qt 레이아웃 및 위젯의 크기변화 동작 정리

 Usage
   - QLayout, QWidget, QtAlignment


Application 개발을 하면서 가장 먼저 해야하는것이 UI 배치이다.


사실 UI 배치가 끝나면 그 다음부터는 기능의 구현이기 때문에 UI 배치를 처음에 잘해야 한다.
그러면서도 유연성 있게 해야한다. 왜냐면, 언제든 상황에 따라서 가장 많이 변하고, 빈번하게 바뀌는 것이 UI 이기 때문이다. ( 그래도 알았으면 하는 것 중 하나는 단 하나의 pixel를 맞추기 위해서 엄청난 고정값이 필요하다는 것이다. 그 고정값을 얻기 위해서 많은 빌드&런을 하는 과정이 필요하다. 이 의미는 무엇이냐?! const 값을 찾기 위해 물리적인 시간이 필요하다는 것이다.)

이러한 UI구성을 우리는 Layout이라고 부르고, Qt의 Layout에 대해서 생각을 정리 하고자 한다.
먼저 기본적인 ui 구성을 아래와 같이 잡는다라고 가정을 해보자






Mainwindow 안에 3개의 위젯이 배치되었다고가정하다.

그럼 여기서 생각해봐야 할것들.

전체 크기가 변할 때 각 위젯들의 크기나 위치가 변화하는 방법이다.
그렇다면 각 위젯들의 크기나 위치가 변하기 위해서는 반드시 필요한 것이 있다.

"기준이 되어야 할 무엇, 즉 고정된 위치 또는 크기의 위젯이다."

만일 크기가 커짐에 따라서, 1-2-3 번이 모두 변한다면 고정된 위젯이나 크기는 필요하지 않다.
기본값만 있으면 된다.

근데 만일 1번은 고정되어 있고, 2-3번만 변하는 상황이라면,
1번값은 고정된 크기와 왼쪽 위치에 있고, 2-3번은 기본 크기와 위치만 있으면 된다.

또한 2-3번은 고정이고, 1번이 width는 고정이고 height가 변한다라고 하면,
2-3번의 크기는 고정이고, 1번의 width또한 고정이고, height 에 대해서만 기본 크기가 있으면 된다.
(이렇게 동작하고 있는 근거는 무엇일까를 확인 해 보면, 각 위젯의 크기가 고정일 경우 resize 이벤트가 발생을 안한다.)

이를 위해 간단한 예제 코드를 적용 해 보았다.


             


             


위그림에서 보듯 기본적으로 크기에 따라, 정렬 방법에 따라서 위젯의 크기와 위치를 조절 할 수 있도록 하였다.
완벽하지 않지만, 기본적인 동작은 모두 가능하다.

그런데, 하나 또 깨달은 것 중 하나는, 하나의 위젯이 크기를 결정짓는 것 중, 정렬 방법이 영향을 미친다는 것이다.

단순히 정렬과 크기는 다르다 라고 생각을 했는데,

크기가 커짐 보다 정렬하기 위한 위치가 더 우선시 되고 있다. 그래서 크기가 고정일 때만 정렬 기능이 동작을 하는 것을 확인 할 수 있다.

물론, 어떻게든 해낼 수 있는 방법은 있겠지만, 단순히 예제 프로그램이기 때문에, 기본 동작에 대해서 기능을 구현해 보았다.

제 방법이 정답이 아니기 때문에, 관련 내용에 대해서 수정 또는 조언을 해주시면 감사하겠습니다.

source : https://github.com/holograming/QtDevZone/tree/master/Src/Layout
binary : https://drive.google.com/open?id=0ByvWiBJz6HrFNXNzaXhSeVJ6VEE

2017년 3월 17일 금요일

QT 프로그램 재시작하는 방법


QProcess를 사용한 현재 실행 중인 process를 재시작 하는 방법

Application이 종료될 때 리턴 코드를 특정 코드(APP_RESTART_COD)로 할당하여,
재시작 하도록 함.

QApplication::exit(APP_RESTART_CODE);


[Ex-1]
1 if (!QProcess::startDetached(QApplication::applicationFilePath(), QApplication::arguments()))
2 {
3     messagebox()
4 }
5 else
6 {
7     // 현재 프로세스 종료
8     app::Application::exit(1);

9 }



[Ex-2]
1 int re = application.exec();
2
3 if (re == APP_RESTART_CODE)
4 {
5     QProcess* proc = new QProcess();
6     proc->start(QApplication::applicationFilePath(), QApplication::arguments());
7     proc->waitForStarted();
8 }