디자이너를 이용하면 메인윈도우도 간단히 만들수 있습니다.
특히 많은 메뉴들과 툴바아이콘들을 배치해야 할 경우 보면서 할수있기에 편리합니다.

디자이너로 메인윈도우를 만들려면, 디자이너를 실행시키고 메인윈도우를 선택합니다.

메인 윈도우 만들기


메인윈도우를 생성하고 나면 메뉴바 위치에 Type Here 라는 문구가 보입니다. 여기서부터 메뉴와 액션들을 추가해 갈수 있습니다.

참고로 여기서부터는 메뉴와 각종 텍스트는 영어로 작성하도록 하겠습니다.
이유는 기본 언어를 영어로 하고, 번역판으로 한국어를 제공하는 방식으로 하기 위해서 입니다.
물론 기본 언어를 한국어로 해도 되고, 국내이용자만을 대상으로 하는 경우라면 그걸로도 충분 할 것입니다.
이에 따른 차이는 나중에 또 별도로 설명하겠습니다.

한번 파일 메뉴와 새 파일 액션을 추가해보세요. Type Here 라는 곳을 더블 클릭하여 &File 이라고 입력한 후 엔터를 누르면 파일 메뉴가 생성됩니다.
이상태에서 파일 메뉴를 클릭하면 메뉴창이 열리고 그 아래에는 또 Type Here 이라는 문구와, Add Seperator 라는 문구가 보입니다.
Type Here를 더블 클릭하고 메뉴를 생성할 때와 같은 요령으로 &New File 이라고 입력하면 새 파일 액션이 생성됩니다.
그런데 새 파일 액션의 오랜쪽에 + 같은 모양의 아이콘이 보일 것입니다.
이 아이콘은 액션을 메뉴로 확장하는 아이콘으로, 하위 메뉴를 만들 때 이용합니다.

메뉴와 액션의 문자열을 고치고 싶을 때는 메뉴상에서 더블 클릭하여 고치면되며, 그외의 속성들을 수정할 때는, 다른 위젯들과 동일하게 Object Inspector와 Property Editor를 이용하여 수정할 수 있습니다.
또한, 액션의 경우 액션만을 위한 Action Editor 라는 것이 제공됩니다.
Action Editor는 디자이너의 기본 레이아웃이라면 오른쪽 하단의 Signal/Slot Editor와 겹쳐져 있으니, Action Editor 탭을 눌러서 표시할 수 있습니다.

Action Editor

Action Editor를 보면 방금 만든 새 파일 액션이 보입니다.
한번 더블 클릭해보면, Edit Action이라는 다이얼로그가 나타납니다.
이 다이얼로그는 Property Editor에서 특히 액션의 경우 자주 편집되는 부분만 모아 놓은 것이라고 생각하면 됩니다.
ToolTip외에는 별도로 항목에 대한 설명은 필요 없어 보입니다.

우선 아이콘을 지정해봅시다.
이전과 마찬가지로 로컬 파일을이용할 수 도 있고, Qt의 리소스를 이용할 수도 있습니다.
Qt의 리소스를 이용하는 경우, 디자이너를 이용하여 리소스를 쉽게 관리할 수 있습니다.
여기서는 Qt 리소스를 이용하는 법도 배울 겸, 리소스를 이용하여 아이콘을 지정해보겠습니다.
Icon 항목의 오른쪽의 ... 버튼을 클릭해보면 Select Resource 다이얼로그가 나타납니다.
하지만 현재 불러온 리소스 파일이 없기 때문에 아무것도 선택할 수 없습니다.
여기서 상단의 연필 모양 버튼을 클릭하면 Edit Resources 다이얼로그가 나타납니다.
이 창의 하단을 보면 왼쪽에 두개의 버튼이 활성화되있는데요, 왼쪽은 새로운 리소스 파일(.qrc)파일을 만드는 버튼이고, 오른쪽은 기존의 리소스 파일을 여는 버튼입니다.

이전에 만들었던 리소스 파일을 열어 보면 이전에 넣어 둔 아이콘 파일이 하나 표시될 것입니다.
여기서는 연습 삼아 새로운 리소스 파일을 만들어 보겠습니다.
열린 리소스 파일을, 왼쪽의 X 버튼으로 닫고, 새 리소스 파일을 만듭니다.
여기서는 이전에 만든 resources.qrc 파일에 덮어 씌우겠씁니다.
이제 오른쪽 버튼들이 활성화 됩니다.
우선 + 버튼을 눌러서 prefix를 추가합니다.
prefix는 리소스에 접근 할때의 최상위 경로로 보통은 / 로 하면됩니다.
그후 오른쪽에서 두번째 버튼으로 리소스를 엽니다.
이전에 첨부한 소스 파일을 보면, img 디렉토리 안에 두개의 이미지 파일이 있습니다.
두개 모두 선택하여 추가 한후 OK 버튼을 누르면 리소스 파일이 편집되어 저장됩니다.
참고로 리소스를 삭제할 때는 제일 오른쪽의 - 버튼을 이용하면 됩니다.
또, 리소스는 Action Editor의 오른쪽 탭에 있는 Resource Browser를 통해서도 열람/편집이 가능합니다.

다시 Select Resource 창으로 돌아왔습니다,
이제 방금 추가한 두개의 이미지를 선택할 수 있습니다.
적당한 이미지를 선택한 후, OK를 누르면 아이콘이 선택된 것을 확인 할 수 있습니다.

그외에 Object name은 원하는 이름으로(저는 newFileAction)으로 입력하시고, Shortcut으로 단축키를지정합니다(저는 Ctrl+N).
단축키는 오른쪽의 화살표 버튼을 클릭한후 실제로 키보드로 원하는 단축키를 누르면 자동으로 입력됩니다.

이것으로 액션편집이 끝났습니다.
이번에는 툴바를 만들어 보겠습니다.
메인 윈도우의 적당히 가운데에서 오른쪽 클릭을 해보면 Add Tool Bar라는 메뉴가 제일 상단에 나타납니다.
이 메뉴를 선택하면 메뉴바 밑에 가느다란 툴바가 추가 됩니다.
툴바가 가느다란 이유는 아직 아무것도 안들어 있기 때문입니다.
여기에 방금 만든 새파일 메뉴를 추가해보겠습니다.
Action Editor에서 추가할 액션을 드래그 하여 툴바에 드랍하면 됩니다.

마지막으로 메인 윈도우의 central widget을 지정해봅시다.
정확히 말하면, 디자이너에서 만든 메인윈도우의 경우 central widget은 무조건 평범한 QWidget이 들어가게됩니다.
그대신 디자이너에서는 그 위젯 안에 다른 위젯을 넣어서 표시할 수가 있습니다.
우리는 텍스트 에디터를 만들고 있으므로 왼쪽에서 Text Edit 위젯을 가져오서 메인 윈도우의 가운데에 놓고, Object Name을 edit로 지정합니다.
그후 방금 내려놓은 Text Edit 외의 적당히 다른 부분을 클릭하면 상단의 레이아웃 툴바가 활성화됩니다.
이상태에서 적당한 레이아웃(여기서는 다른 위젯을 배치하지는 않으므로 아무거나 상관없습니다).
여기서 레이아웃을 지정해야 하는 이유는 자동으로 크기가 조절되도록 하기 위해서 입니다.
저는 Lay Out Horizontally 를 선택하였습니다.
그런데 이상태로는 Text Edit 상하좌우로 여백이 들어가 버립니다.
이 여백은, 레이아웃을 넣은 위젯의 property에서 없앨 수가 있습니다.
Object Inspector에서 방금 레이아웃을 넣은 위젯(아마도 특별히 수정하지 않았으면 centralwidget이라고 되어있는 위젯)을 선택한 후, Property Editor의 가장 아래쪽을 보면 Layout 이라는 항목이 보일 것입니다.
여기서 LayoutLeftMargin, LayoutRightMargin, LayoutTopMargin, LayoutBottomMargin을 0으로 입력해주면 Text Edit 주변의 여백이 없어질 것입니다.

마지막으로 메인윈도우의 프로퍼티에서 윈도우 아이콘으로 리소스의 document-edit.png 파일을 선택해주고, 윈도우 타이틀도 적당히 적어줍시다(저는 Text Editor라고 해주었습니다).
이상태에서 Ctrl+R을 눌러 미리보기를 해봅시다.
겉모습만 보면 이전에 만든 texteditor 프로그램과 동일 할 것입니다.
이 상태에서 한번 툴바의 버튼에 마우스 커서를 올려놓고 가만히 둬보세요.
New File이라는 작은 텍스트가 표시됩니다.
이것이 아까 설명하지 않고 지나간 액션의 ToolTip입니다.
기본적으로는 액션의 Text가 그대로 표시되지만, ToolTip을 적당히 수정하여 원하는 텍스트가 표시되게 할 수도 있습니다.

여기서 작성한 파일을 mainwindow.ui라는 이름으로 저장한 후, 실제 코드에서 불러와서 적용합니다.
우선 새로운 ui파일을 만들었으므로 프로필 파일(texteditor.pro)에 다음과 같이 FORMS 항목을 추가해줍니다.

FORMS += mainwindow.ui

그리고 mainwindow.cpp를 대대적으로 수정해줍니다.

[code]#include "mainwindow.h"
#include "ui_mainwindow.h"

struct MainWindow::Data {
    Ui::MainWindow ui;
};

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), d(new Data) {
    d->ui.setupUi(this);
   
    connect(d->ui.newFileAction, SIGNAL(triggered()), this, SLOT(newFile()));
}

MainWindow::~MainWindow() {
    delete d;
}

void MainWindow::newFile() {
    d->ui.edit->clear();
}
[/code]
기본적인 요령은 이전에 설명한 폼 디자인 적용하기와 마찬가지로, setupUi() 함수를 호출 하여 줍니다.
이전 소스와 비교해보면 아시겠지만 메인 윈도우에서 메뉴바나 툴바를 생성하는 과정이 디자이너를 이용함으로서 생략되어 훨씬 간략한 소스가 되었습니다.
그리고 액션이나 Text Edit는 이제 Ui::MainWindow의 멤버이기 때문에 d->edit 등은 d->ui.edit 등으로 수정해주었습니다.

마지막으로 소스파일을첨부하고 디자이너를 이용한 메인윈도우 만들기를 마칩니다.
첨부한 소스파일에는, 이외에도 별도의 설명없이 간단히 구현할 수 있는 몇가지 메뉴가 더 추가되어있습니다.
소스코드를 보시고 이해가 안되시면 질문해주세요.

texteditor.tar.gz

예제 소스코드


Posted by xylosper

2009/09/08 09:42 2009/09/08 09:42
, , , , ,
Response
No Trackback , a comment
RSS :
http://xylosper.net/rss/response/134

Trackback URL : http://xylosper.net/trackback/134

Qt에 대하여 - 8. Qt Designer - 폼 디자인

복잡한 레이아웃, 일일이 손으로 짤려면 귀찮고 나중에 좀 수정하기도 어렵죠.

이럴때 Qt Designer가 유용하게 쓰일 것입니다.

Qt Designer는 Qt로 프로그램을 만들떄 GUI적인 부분을 쉽게 디자인 할 수 있도록 도와주는 프로그램입니다.

소스로부터 컴파일 한경우는 자동으로 컴파일되어서 만들어지지만, 리눅스에서 패키지를 다운 받아서 Qt를 설치하신 분은 아마 designer는 별도로 설치하셔야 할겁니다(이부분은 배포판마다 다르므로 사용하시는 배포판의 패키지 저장소에서 검색해보세요).
Qt Designer

Qt Designer의 모습

Qt Designer(앞으로 그냥 디자이너 라고 하겠습니다)를 실행하면, 뭔가 묻는 다이얼로그가 나옵니다만, 일단은 무시해보시고 창을 닫으면 위와같은 모습이 나타날 것입니다.

혹시 위 스샷과 달리 여러개의 창이 따로따로 뜬다면 Multiple Top-Level Windows 모드이기 때문입니다.

Edit->Preferences 에서 User Interface Mode설정에 따라 인터페이스를 변경할 수 있습니다.

개인적으로 Docked Window모드를 선호하기 때문에 앞으로도 이 화면으로 설명하겠습니다(아마 창이 따로 노는거 말곤 다른 점 없을 것같습니다).

각 번호가 적혀있는 부분에 대해서 설명해보면..

1: Widget Box입니다. 각종 위젯들이 등록되어있어서 이걸 끌어다가 놓는 것만으로 위젯을 생성할 수 있습니다.
2. Object Inspector입니다. 객체들간의 포함관계가 트리형태로 제공됩니다. 객체의 갯수가 많아져서 찾기 힘들다거나, 객체가 겹쳐있어서 선택하기 힘든 경우에 유용합니다.
3. Property Editor입니다. 선택된 객체의 프로퍼티를 설정할 수 있습니다.
4. Signal/Slot Editor입니다. 연결된 시그널과 슬롯 페어가 표시되며, 여기서 시그널/슬롯 페어를 추가하는 것도 가능합니다.
5. Resource Editor입니다. 간편하게 리소스 파일을 열고 편집할 수 있습니다.
6. Action Editor입니다. 액션 클래스의 객체들을 편집할 수 있습니다.

여기서 5, 6은 아직 설명하지 않은 리소스나 액션이 들어가기 떄문에 이번에는 이용하지 않습니다.

뭐 암만 말로 열심히 설명해도, 직접 해보는 것만 못합니다.

이번엔 여러가지 위젯으로 간단해보이지만 손으로 짤려면 귀찮은 레이아웃의 폼을 만들어보면서, 디자이너를 이용하면 얼마나 간단하게 폼디자인을 할수 있는지 알아보겠습니다.

디자이너를 열면(혹은 위 화면에서 File->New Form) New Form 다이얼로그가 나타납니다.

왼쪽에 Dialog with Buttons Bottom 등의 몇가지 선택사항이 나타납니다.

이것들은 기본적인 위젯의 템플릿을 나타냅니다.

다이얼로그를 만들 것이라면 위의 셋중에 하나를, 위젯을 만들 것이라면 맨 아래의 Widget을 선택합니다(Main Window역시 아직 설명하지 않은 부분이므로 패스합니다).

위젯은 다른 위젯의 일부로 포함될 수 있지만, 다이얼로그는 무조건 별도의 창으로 나타나게 됩니다.

이번 예제는 다이얼로그를 선택하되, 직접 버튼을 추가할 예정이므로 Dialog without Buttons를 선택합니다.

사용자 삽입 이미지
위와 같이 가운데 부분에 새로운 창이 나타납니다.

이 창이 우리가 앞으로 디자인해갈 부분입니다.

먼저 오른쪽의 Object Inspector에서 위젯이 선택되어있는 것을 확인하고, Property Editor에서 이 위젯의 이름을 지정해줍니다.

이 이름은 객체에 따라서 역할이 다릅니다.

지금 수정하려는 최상위 위젯의 이름은, 나중에 생성될 C++코드에서 이 위젯의 클래스이름이 됩니다.

반면에 이제부터 여기에 추가해갈 위젯들의 이름은, C++코드상에서 그 위젯을 가리키는 변수명이 됩니다.

적당히 objectName란에 TestWidget이라고 적어줍니다.

이제 왼쪽의 Widget Box에서 필요한 위젯들을 가져와서 아래와 같이 배치합니다.
위젯을 배치한 모습

위젯을 배치한 모습


위젯을 추가할때는 Widget Box에서 원하는 위젯을 선택하고 마우스로 위의 폼으로 끌고와서 적당한 위치에 놓습니다.

이름이 적혀있는 위젯들은 이름을 보면 어떤 것인지 알수 있으므로 생략하고, 이름이 적혀있지 않은 위젯들만 무엇인지 적어보면, 첫째줄 두번째는 Line Edit, 두번쨰 줄의 가운데는 Horizontal Slider, 그 오른쪽은 Spin Box, 셋째줄의 스프링처럼 생긴것은 Horizontal Spacer, Group Box안의 가장 오른쪽 위젯은 Combo Box, 그리고 맨 아래의 OK/Cancel버튼은 Push Button이 아니라 Button Box 라는 녀석입니다.

배치할때는 정확하게 위치를 정해서 할 필요없이 대강 위젯들간의 위치관계만 생각해서 놓으면 됩니다.

추가가 끝났으면, 이번엔 아래 그림처럼 각 위젯의 텍스트를 수정합니다.
수정된 다이얼로그

수정된 다이얼로그


텍스트도 프로퍼티이므로 Property Editor에서 text 항목을 찾아서 수정하면됩니다만, text 프로퍼티를 가지고 있는 위젯들은 대게 더블 클릭하면 바로 text를 수정할 수 있게 되어있습니다.

또 Combo Box에는 RGB, CMYK, YUV 세개의 항목이 들어가있습니다. 역시 더블클릭으로 쉽게 추가하고 수정할 수 있습니다.

이외에도 각 위젯들의 각종 프로퍼티들은 거의다 Property Editor에서 수정가능합니다.

예를 들어 위 그림을 보면 그룹박스에 체크표시가 있는 것을 알수 있는데요, 그룹박스의 checkable 항목을 true로 설정하면 그룹박스도 체크할수있도록 됩니다.

다음으로 실제 소스코드에서 참조할 위젯들은 적당한 변수명을 정해줍니다.

이경우는 디자인을 위한 예제이므로 대부분 실제 코드에서 참조할일이 없기 때문에 거의 다 그냥 두어도 됩니다만, RGB, CMYK, YUV 라디오버튼의 objectName을 각각 rgb_radio, cmyk_radio, yuv_radio라고 하고, 콤보박스는 color_combo라고 합니다((위에서 설명했듯 이 이름은 클래스 이름이 아니라 변수명입니다).

이제 레이아웃을 짜봅니다.

우선 색반전하기 체크박스와 그옆의 미리보기 버튼, 그리고 스프링(-_-;)을 쉬프트키를 누른 상태로 차례대로 선택하여 동시에 세개가 선택된 상태가 되게 합니다.

그 후, 마우스 오른쪽 버튼을 클릭하고 Lay out -> Lay out Horizontal을 선택하면 이 셋이 하나의 레이아웃으로 묶이게 됩니다.

참고로 선택후 툴바의 Lay out Horizontal 버튼을 이용해도 됩니다.

이런식으로 위젯들을 선택해가면서 레이아웃을 눌러주면 됩니다.

다음으로 그룹박스의 레이아웃을 만듭니다.

당연히 Horizontal 레이아웃을 쓸것인데, 이경우는 그룹박스만 선택한 채로 Lay out Horizontal을 선택하면, 자동으로 그룹박스 내부의 위젯들이 Horizontal 레이아웃으로 배열됩니다.

이렇게 한 위젯안에 다른 위젯이 들어있는 경우는, 그 위젯들을 포함하고 있는 위젯을 선택한 상태에서 레이아웃을 선택해줍니다.

이번엔 슬라이더와 스핀박스를 선택하고 Horizontal 레이아웃을 짭니다.

그리고 다음과 같이 적당히 위젯을 예쁘게(-_-;) 배치합니다.

재배치된 모습

재배치된 모습

완벽할 필욘 없지만 가급적이면 줄이 맞게 배치하는게 좋습니다. 이번엔 Grid Lay out이란 것을 이용합니다.

지난시간에 설명하지 않은 레이아웃인데요, QGridLayout이라는 클래스로 구현되며, 표와 같은 모습은 레이아웃을 짜줍니다.

셀병합도 가능합니다.

위의 그림처럼 위젯들을 선택하고, Lay out in a Grid 를 선택하면, 자동으로 가장 적합한 모양의 그리드가 생성됩니다.

예를 들어 맨밑의 색반전하기 부분의 레이아웃은 자동으로 두칸을 병합하여 한줄을 다 차지하도록 됩니다.

마지막으로 남은 부분을 전부 세로로 나열하기 위해서 TestDialog를 선택하고 Lay out Vertical을 선택한후 적당한 크기로 만들기 위해 Adjust Size를 선택하면 다음과 같은 모습이 될것입니다.
최종 모습

최종 모습

이제 폼을 짜는건 끝났습니다. 하지만 디자이너의 기능은 이게 다가 아닙니다.

디자이너상에서 기본적인 시그널/슬롯도 연결해주는게 가능합니다.

예를 들어, 슬라이더를 움직이면 자동으로 스핀박스의 값도 바뀌고, 반대로 스핀박스의 값을 변경하면 자동으로 슬라이더가 움직이게 할려고 합니다.

스핀박스와 슬라이더는 값이 변경되면 valueChanged(int)라는 시그널을 뱉고, 동시에 setValue(int)라는 값을 설정해주는 슬롯도 있습니다.

그러므로 스핀박스의 valueChanged를 슬라이더의 setValue에, 슬라이더의 valueChanged를 스핀박스의 setValue로 연결해주면 됩니다.

먼저 슬라이더를 움직이면 스핀박스의 값이 바뀌도록 해봅시다.

우선 Edit 메뉴나 툴바에서 Edit Signals/Slots를 선택하여 시그널/슬롯 편집모드로 바꿉니다.

그리고 시그널을 뱉는 슬라이더를 클릭한 상태에서 마우스를 드래그하면 화살표가 나타납니다.

드래그 한채로 이 화살표를 시그널을 연결할 위젯위로 가져가서 놓으면 아래와 같이 연결할 시그널과슬롯을 묻는 다이얼로그(Configure Connection)가 나타납니다.
시그널/슬롯 연결 대화창

시그널/슬롯 연결 대화창

위와같이 연결할 시그널(valueChanged)와 슬롯(setValue)를 선택하고 OK를 누르면 이들이 연결됩니다.

참고로 선택된 시그널과 인자가 맞지 않아서 연결할 수 없는 슬롯은 선택할 수 없게 되어있습니다.

이런식으로 이번엔 스핀박스의 valueChanged시그널을 슬라이더의 setValue슬롯에 연결합니다.

이번엔 색반전하기 체크박스가 체크되어있을 떄만 미리보기가 가능하게 할려고 합니다.

체크박스는 체크상태가 변경될때마다 toggled(bool)이란 시그널을 뱉습니다. 이것을 미리보기 버튼의 setEnabled(bool)로 연결합니다.

그런데, 이때 Configure Connection창에서 버튼의 슬롯 목록을 보면 setEnabled(bool)이 안보일 것입니다.

setEnabled(bool)이란 슬롯은 QPushButton 자체의 슬롯이라기보다는, QWidget 클래스로부터 상속받은 슬롯이고, 처음 상태에서는 상속받은 시그널이나 슬롯은 나타나지 않게 되어있기 때문입니다.

이럴 때는 Configure Connection창의 하단에 있는 Show all signals and slots를 선택하면 상속받은 시그널과 슬롯까지 전부 표시해주므로, 이걸 체크하고 선택하면 됩니다.

마지막으로 버튼그룹의 accepted를 전체 다이얼로그(위젯을 배치하지 않은 빈공간으로 가져가면 됩니다. 화살표가 마치 접지마크 비슷한 상태입니다)의 accept로, rejected를 reject로 연결합니다.

accepted는 OK버튼이 눌렸을때, rejected는 Cancel이 눌렸을 때 뱉어집니다. 그래서 OK가 눌리면 다이얼로그가 '받아들여졌다(예를 들어, 설정 창이라면 설정을 적용한다든가)'라는 의미로 accept로 연결하고, Cancel이 눌리면 취소되었단 의미로 reject로 연결합니다.

이 두 슬롯은 모두 다이얼로그를 안보이게 하는 역할을 하고, 모달 다이얼로그의 반환값을 설정합니다.
연결된 시그널과 슬롯들

연결된 시그널과 슬롯들


이제 슬롯이 모두 연결되었는데요, 프로그램을 짜기 전에 한번 제대로 작동하는지 확인하고 싶습니다.

이럴땐, Form메뉴의 Preview(단축키:Ctrl+R)를 선택하면 미리보기가 나타납니다.

이상태에서 연결된 슬롯들은 모두 작동합니다.

예를 들어 슬라이더를 움직이면 스핀박스의 값이 바뀔 것이고, 체크박스를 체크했다가 해재할때마다 버튼은 enbaled/disabled 상태가 반복됩니다.

마지막으로 OK나 Cancel을 누르면 창을 닫게 됩니다.

이제 폼디자인이 끝났습니다.

원래는 이번회에 실제로 코드상에서 디자인한 폼을 어떻게 가져다 쓰는지까지 할려고 했습니다만, 그림이 많아서 내용이 길어진 관계로(언제나 길어지는 느낌입니다만-_-;) 실제로 프로그램을 만드는 것은 다음 시간에 소개하도록 하겠습니다.

Posted by xylosper

2008/04/06 19:08 2008/04/06 19:08
, ,
Response
No Trackback , 3 Comments
RSS :
http://xylosper.net/rss/response/114

Trackback URL : http://xylosper.net/trackback/114


Notices

Archives

Calendar

«   2010/09   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    

Site Stats

Total hits:
173475
Today:
20
Yesterday:
81