wxWidgets에서 글을 작성한 후에 실행 취소를 하는 기능을 제공해보자.

 실행 취소(Undo)는 wxWidgets에서 ID를 지원해주기 때문에 wxMain.h에서 ID을 추가할 필요없다.

 

 그래서 이벤트 핸들러만 제작하면 되는데.

 wxMain.h에 다음과 같이 추가해주자.

1
2
3
4
5
6
 
    // Edit 메뉴에 적용할 이벤트 핸들러
    void OnUndo(wxCommandEvent& event);
    void OnSelectAll(wxCommandEvent& event);
    void OnInsertDateTime(wxCommandEvent& event);
 
cs

 

이후에 Edit의 하위 메뉴를 추가하주자.

1
2
3
4
5
6
    m_menuEdit = new wxMenu;
    m_menuEdit->Append(wxID_UNDO, "&Undo\tCtrl+Z""Undo the last action");
    m_menuFile->AppendSeparator();
    m_menuEdit->Append(ID_SELECT_ALL, "&Select All\tCtrl+A""Select all text");
    m_menuFile->AppendSeparator();
    m_menuEdit->AppendCheckItem(ID_DATETIME, "&DateTime\tF5""DateTime");
cs

 

이 후에 이벤트 핸들러랑 연결될 수 있게 적용해준다.

1
2
3
4
    // 메뉴 Edit에 관련된 이벤트 핸들러
    Bind(wxEVT_MENU, &MyFrame::OnUndo, this, wxID_UNDO);
    Bind(wxEVT_MENU, &MyFrame::OnInsertDateTime, this, ID_DATETIME);
    Bind(wxEVT_MENU, &MyFrame::OnSelectAll, this, ID_DATETIME);
cs

 

이렇게 하면, 이벤트 핸들러인 OnUndo랑 연동된다.

이제 OnUndo를 정의해주면, 실행 취소가 가능하다.

여기서 실행 취소는 wxTextCtrl에서 실행 취소 기능을 지원해주기 때문에 OnUndo는 그걸 이용하면 된다.

1
2
3
4
5
6
void MyFrame::OnUndo(wxCommandEvent& event) {
    if (m_textControl->CanUndo()) {
        m_textControl->Undo();
    }
}
 
cs

 

실행 취소가 활성화 비활성화로 실행이 존재할 경우에 활성화되고 그런것이 전혀 없다면, 실행 취소를 비활성화 시키는 방식을 구현하기 위해서는 메뉴 항목의 상태를 동적으로 업데이트하는 장치가 필요하다.

wxWidgets에서는 'wxUpdateUIEvent'라는 기능을 지원해준다.

이걸 이용하는 방법을 위해서

wxMain.h에 이벤트 핸들러를 선언한다.

1
2
    // 메뉴 동적 활성화 하기 위한 이벤트 핸들러
    void OnUpdateUndo(wxUpdateUIEvent& event);
cs

 

 

wxMain.cpp에서 OnUpdateUndo라는 이벤트 핸들러를 wxEVT_UPDATE_UI 종류로 연결시켜준다.

1
2
    // 메뉴바 갱신 이벤트 핸들러
    Bind(wxEVT_UPDATE_UI, &MyFrame::OnUpdateUndo, this, wxID_UNDO);
cs

 

이렇게 해서 wxMain.h에 선언했던 'OnUpdateUndo'를 정의해준다.

1
2
3
4
5
// 메뉴바 갱신 이벤트 핸들러
void MyFrame::OnUpdateUndo(wxUpdateUIEvent& event)
{
    event.Enable(m_textControl->CanUndo());
}
cs

 

 실행취소가 가능할때 활성화되고,실행취소가 불가능하면 비활성화를 적용이 가능해진다.

 

Posted by JunkMam
,

 C언어에서는 프로그래머가 출력하는 것을 간단하게 지원해주는 장치가 있다.

 그걸 사용하기 위해서 지원해주는 라이브러리로 'stdio.h'[Standard I/O]이다.

 

 stdio.h을 사용한 간단한 예제 코드를 작성해보자.

1
2
3
4
5
6
7
8
9
#include <stdio.h>
 
int main(int argc, char** argv)
{
    printf("Hello, World!\n");
 
    return 0;
}
 
cs

 

이것은 printf라는 함수를 이용해서 간단한 문장을 작성한 것이며, \n은 '개행 문자'라고하여, 다음 줄로 넘어간 후 콘솔의 첫번째 위치로 이동하는 걸 뜻한다.

 특수 문자 및 특수 기능을 하는 것은 '\'을 붙여서 작성한다.

 

 예을 들어서 Hello, World!을 쌍따옴표(")에 둘려 싸게 하고 싶다면,

1
2
3
4
5
6
7
8
9
#include <stdio.h>
 
int main(int argc, char** argv)
{
    printf("\"Hello, World!\"\n");
 
    return 0;
}
 
cs

 

printf말고 다양한 출력 기능이 있는데.

puts(put string)과, putchar(put character)가 있다.

puts는 문자열을 출력한 후 끝에 "\n"을 붙여주고,

putchar는 한 글자씩 출력한다.

 

puts의 예제

1
2
3
4
5
6
7
#include <stdio.h> 
 
int main() {
    puts("Hello, World!");
    return 0;
}
 
cs

 

 

putchar의 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
 
int main() {
    putchar('H');
    putchar('e');
    putchar('l');
    putchar('l');
    putchar('o');
    putchar(',');
    putchar(' ');
    putchar('W');
    putchar('o');
    putchar('r');
    putchar('l');
    putchar('d');
    putchar('!');
    putchar('\n');
 
    return 0;
}
 
cs

 

 

이렇게 된다.

이런 함수들은 컴퓨터에는 문제가 되지 않지만, 그 외 기기들에게는 구현되지 않는 경우가 있다.

출력하기 위한 방식은 특정 메모리, 혹은 파일에 저장시킨 후 그 정보를 해당 기기에 전송하는 방식이다.

 

통신을 통한다. 라는 것인데.

컴퓨터의 C언어에서 유사한걸 코드를 작성할 수 있다.

 

파일 방식으로 화면에 출력하는 방법.

1
2
3
4
5
6
7
8
9
#include <stdio.h>
 
int main() {
    const char msg[] = "Hello, World!\n";
    fwrite(msg, sizeof(char), sizeof(msg) - 1, stdout);
 
    return 0;
}
 
cs

 

stdout은 stdio.h에서 지원해주는 출력용 파일이고, stdout은 모니터 및 OS에서 인식하는 출력 장치에 해당 데이터를 출력하도록 만든다. 그래서 printf나 puts와 동일하게 콘솔에 해당 문자열이 출력하게 된다.

 

 

'프로그래밍 > C 언어' 카테고리의 다른 글

[C] 제어(1) - 조건문 -  (0) 2024.02.17
[C] 연산자  (0) 2024.02.16
[C] 상수와 변수  (0) 2024.02.15
[C] 기본 구조  (1) 2024.02.13
Posted by JunkMam
,

 wxMain.h

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#pragma once
#include "wx/wx.h"
#include <wx/filedlg.h>
#include <wx/textctrl.h>
#include <wx/splitter.h>
 
// Font Dialog
#include <wx/fontdlg.h>
 
// 파일을 읽어 들이기 위한 용도.
#include <fstream>
#include <sstream>
 
#include "wxOptionsDialog.h"
 
enum
{
    ID_QUIT,
    ID_SAVE_AS,
    ID_SELECT_ALL,
    ID_DATETIME,
    ID_WordWarp,
    ID_FontSetting,
    ID_StatusBar,
};
 
enum {
    MY_EVENT_ID = 10001,
};
 
// 메뉴 항목 ID 정의
enum
{
    ID_NEW_WINDOW = wxID_HIGHEST + 1 // 새 창을 위한 고유 ID
};
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title);
 
    void OnQuit(wxCommandEvent& event);
 
private:
    wxTextCtrl* m_textControl;
 
    // 현재 파일의 경로를 저장하는 변수
    wxString m_currentFileName;
    wxString m_currentFilePath;
 
 
    //wxOptionDialog* m_dialog;
    wxFont* m_font;
 
    wxStatusBar* m_statusBar;
 
    // 메뉴바 및 메뉴 변수.
    wxMenuBar* m_menuBar;
    wxMenu* m_menuFile;
    wxMenu* m_menuEdit;
    wxMenu* m_menuFormat;
    wxMenu* m_menuView;
 
    // File 메뉴에 적용할 이벤트 핸들러
    void OnNew(wxCommandEvent& event);
    void OnNewWindow(wxCommandEvent& event);
    void OnOpen(wxCommandEvent& event);
    void OnSave(wxCommandEvent& event);
    void OnSaveAs(wxCommandEvent& event);
    void OnButtonClick(wxCommandEvent& event);
 
    // Edit 메뉴에 적용할 이벤트 핸들러
    void OnSelectAll(wxCommandEvent& event);
    void OnInsertDateTime(wxCommandEvent& event);
 
    // Format 메뉴에 적용할 이벤트 핸들러
    void OnToggleWordWrap(wxCommandEvent& event);
    void OnFontSetting(wxCommandEvent& event);
 
    // View 메뉴에 적용할 이벤트 핸들러
    void OnToggleStatusBar(wxCommandEvent& event);
 
    // 이벤트를 받기 위한 메소드
    void OnMyCustomEvent(MyCustomEvent& event);
};
 
cs

 

 wxMain.cpp

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#include "wxMain.h"
 
wxIMPLEMENT_APP(MyApp);
 
bool MyApp::OnInit()
{
    MyFrame* frame = new MyFrame("No Title - Notepad");
    frame->Show(true);
    return true;
}
 
MyFrame::MyFrame(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title)
{
    m_menuFile = new wxMenu;
    m_menuFile->Append(wxID_NEW, "&New\tCtrl-N""New a Notepad");
    m_menuFile->Append(ID_NEW_WINDOW, "&New Windows\tCtrl+Shift+N""Open a new window.");
    m_menuFile->Append(wxID_OPEN, "&Open\tCtrl-O""Open a file");
    m_menuFile->Append(wxID_SAVE, "&Save\tCtrl-S""Save the file");
    m_menuFile->Append(ID_SAVE_AS, "&Save As\tCtrl+Shift-S""Save the file");
    m_menuFile->AppendSeparator();
    m_menuFile->Append(ID_QUIT, "E&xit\tAlt-X""Exit Program");
 
    m_menuEdit = new wxMenu;
    m_menuEdit->Append(ID_SELECT_ALL, _("&Select All\tCtrl+A"), _("Select all text"));
    m_menuFile->AppendSeparator();
    m_menuEdit->AppendCheckItem(ID_DATETIME, "&DateTime\tF5""DateTime");
 
    m_menuFormat = new wxMenu;
    m_menuFormat->AppendCheckItem(ID_WordWarp, "Word &Wrap\tCtrl+W""Toggle word wrapping.");
    m_menuFormat->Append(ID_FontSetting, "&Font""Font Set Menu");
 
    m_menuView = new wxMenu;
    m_menuView->AppendCheckItem(ID_StatusBar, "Show &StatusBar""Toggle Status Bar.");
    
    m_menuBar = new wxMenuBar;
    m_menuBar->Append(m_menuFile, "&File");
    m_menuBar->Append(m_menuEdit, "&Edit");
    m_menuBar->Append(m_menuFormat, "F&omat");
    m_menuBar->Append(m_menuView, "&View");
 
    SetMenuBar(m_menuBar);
 
    m_textControl = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
 
    // sizer를 생성하여 텍스트 컨트롤의 크기를 조정합니다.
    wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
    sizer->Add(m_textControl, 1, wxEXPAND | wxALL, 0); // wxEXPAND는 컨트롤이 sizer의 가능한 모든 공간을 차지하도록 합니다. 1은 비율을 의미하며, 이 경우 다른 컨트롤이 없으므로 전체 크기를 차지합니다.
 
    // 프레임에 sizer를 설정합니다.
    this->SetSizer(sizer);
    this->Layout(); // sizer를 강제로 다시 계산하여 적용합니다.
 
    // 폰트 설정
    wxFont font(16, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
    m_textControl->SetFont(font);
 
    //m_statusBar = new wxStatusBar(this);
    m_statusBar = CreateStatusBar();
    SetStatusText("Ready");
    // ID_StatusBar 메뉴 항목을 자동으로 체크되어 있도록 설정
    m_menuView->Check(ID_StatusBar, true);
 
    // 이벤트 핸들러 연결
    Bind(wxEVT_MENU, &MyFrame::OnNew, this, wxID_NEW);
 
    // MyFrame 생성자 또는 초기화 함수 내
    Bind(wxEVT_MENU, &MyFrame::OnNewWindow, this, ID_NEW_WINDOW);
 
    Bind(wxEVT_MENU, &MyFrame::OnOpen, this, wxID_OPEN);
    Bind(wxEVT_MENU, &MyFrame::OnSave, this, wxID_SAVE);
    Bind(wxEVT_MENU, &MyFrame::OnSaveAs, this, ID_SAVE_AS);
 
    Bind(wxEVT_MENU, &MyFrame::OnQuit, this, ID_QUIT);
 
    // 메뉴 Edit에 관련된 이벤트 핸들러
    Bind(wxEVT_MENU, &MyFrame::OnInsertDateTime, this, ID_DATETIME);
    Bind(wxEVT_MENU, &MyFrame::OnSelectAll, this, ID_DATETIME);
 
    // 메뉴 Format에 관련된 이벤트 핸들러
    Bind(wxEVT_MENU, &MyFrame::OnToggleWordWrap, this, ID_WordWarp);
    Bind(wxEVT_MENU, &MyFrame::OnFontSetting, this, ID_FontSetting);
 
    // 메뉴 View에 관련된 이벤트 핸들러
    Bind(wxEVT_MENU, &MyFrame::OnToggleStatusBar, this, ID_StatusBar);
 
    // 이벤트 처리기 등록
    Bind(MY_CUSTOM_EVENT, &MyFrame::OnMyCustomEvent, this);
}
 
void MyFrame::OnQuit(wxCommandEvent& event)
{
    Close(true);
}
 
void MyFrame::OnNew(wxCommandEvent& event) {
    // 텍스트 컨트롤의 내용을 비웁니다.
    m_textControl->Clear();
 
    // 타이틀에 메시지를 새로 작성합니다.
    wxString titleNames = "No Title";
    titleNames += " - Notepad";
    SetTitle(titleNames);
 
    // 상태 표시줄에 메시지를 표시합니다.
    SetStatusText("New document created.");
}
 
// MyFrame 클래스 내
void MyFrame::OnNewWindow(wxCommandEvent& event)
{
    // 새로운 창을 생성하고 표시
    MyFrame* newFrame = new MyFrame("No Title - Notepad");
    newFrame->Show(true);
}
 
void MyFrame::OnOpen(wxCommandEvent& event)
{
    wxFileDialog openFileDialog(this, _("Open TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
 
    wxString openFileName = m_currentFileName;
    wxString openFilePath = m_currentFilePath;
 
    switch (openFileDialog.ShowModal()) {
    case wxID_OK: {
        openFileName = openFileDialog.GetFilename();
        // 세이브 및 적용이 완료했을 경우.
        openFilePath = openFileDialog.GetPath();
        break;
    }
    case wxID_CANCEL: {
        return// 사용자가 취소했을 때
    }
    }
 
    std::ifstream file(openFilePath.ToStdString());
    // 파일을 열고 텍스트 컨트롤에 내용을 로드합니다.
    if (m_textControl->LoadFile(openFilePath)) {
        std::stringstream buffer;
        buffer << file.rdbuf(); // 파일의 내용을 buffer에 읽어 들입니다.
        file.close(); // 파일을 닫습니다.
 
        // textControl의 내용을 갱신합니다.
        m_textControl->SetValue(buffer.str());
        //textControl->SetLabelText(buffer.str());
        m_currentFileName = openFileName;
        m_currentFilePath = openFilePath;
        
        wxString titleNames = m_currentFileName;
        titleNames += " - Notepad";
        // 타이틀을 열린 파일의 이름으로 설정합니다.
        SetTitle(titleNames);
 
    }
    else {
        wxMessageBox("Cannot open File!""Error", wxOK | wxICON_ERROR);
    }
}
 
void MyFrame::OnSaveAs(wxCommandEvent& event)
{
    wxFileDialog saveFileDialog(this, _("Save TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
 
    wxString saveAsFileName;
    wxString saveAsFilePath;
 
    switch (saveFileDialog.ShowModal()) {
    case wxID_OK: {
        saveAsFileName = saveFileDialog.GetFilename();
        saveAsFilePath = saveFileDialog.GetPath();
        break;
    }
    case wxID_CANCEL: {
        return;
    }
    }
 
    // 사용자가 선택한 파일 경로를 저장합니다.
    if (!m_textControl->SaveFile(saveAsFilePath))
    {
        wxMessageBox("Could not save the file!""Error", wxOK | wxICON_ERROR);
        return;
    }
 
    // 파일이 성공적으로 저장되었다면, 현재 파일 경로를 업데이트하고 타이틀을 설정합니다.
    m_currentFileName = saveAsFileName;
    m_currentFilePath = saveAsFilePath;
    wxString titleNames = m_currentFileName;
    SetTitle(titleNames + " - Notepad"); // 타이틀 업데이트
 
    // 상태 표시줄에 메시지를 표시합니다.
    SetStatusText("File saved successfully.");
}
 
void MyFrame::OnSave(wxCommandEvent& event)
{
    wxFileDialog saveFileDialog(this, _("Save TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
 
    wxString saveFileName = m_currentFileName;
    wxString saveFilePath = m_currentFilePath;
 
    // 경로가 비어있는 경우엔.
    if (m_currentFilePath.IsEmpty()) {
        switch (saveFileDialog.ShowModal()) {
        case wxID_CANCEL: {
            return;
        }
 
        case wxID_OK: {
            saveFileName = saveFileDialog.GetFilename();
            // 세이브 및 적용이 완료했을 경우.
            saveFilePath = saveFileDialog.GetPath();
            break;
        }
        }
    }
 
    // 현재 텍스트 컨트롤의 내용을 파일에 저장합니다.
    if (!m_textControl->SaveFile(saveFilePath)) {
        // 현재 텍스트의 내용을 파일에 저장하지 못한다면.
        wxMessageBox("Could Not save the File!""Error", wxOK);
        return;
    }
 
    m_currentFileName = saveFileName;
    m_currentFilePath = saveFilePath;
 
    wxString titleNames = m_currentFileName;
    titleNames += " - Notepad";
    // 타이틀을 열린 파일의 이름으로 설정합니다.
    SetTitle(titleNames);
}
 
void MyFrame::OnSelectAll(wxCommandEvent& event) {
    m_textControl->SelectAll();
}
 
void MyFrame::OnInsertDateTime(wxCommandEvent& event) {
    // 현재 날짜와 시간을 가져옴.
    wxDateTime now = wxDateTime::Now();
    // 현재 날짜와 시간을 기본 형식으로 문자열로 변환.
    wxString dateTimeStr = now.Format();
 
    m_textControl->WriteText(dateTimeStr);
}
 
void MyFrame::OnToggleWordWrap(wxCommandEvent& event)
{
    bool isChecked = m_menuFormat->IsChecked(ID_WordWarp);
    m_textControl->SetWindowStyleFlag(isChecked ? (m_textControl->GetWindowStyleFlag() | wxTE_WORDWRAP) : (m_textControl->GetWindowStyleFlag() & ~wxTE_WORDWRAP));
    m_textControl->Refresh(); // 화면 갱신
}
 
void MyFrame::OnFontSetting(wxCommandEvent& event)
{
    /*dialog = new wxOptionDialog(this, wxID_ANY, "Settings");
    dialog->ShowModal();*/
 
    wxFontData fontData;
    fontData.SetInitialFont(m_textControl->GetFont());
    fontData.SetColour(m_textControl->GetForegroundColour());
 
    wxFontDialog fontDialog(this, fontData);
    if (fontDialog.ShowModal() == wxID_OK)
    {
        wxFontData retData = fontDialog.GetFontData();
        wxFont font = retData.GetChosenFont();
        wxColour colour = retData.GetColour();
 
        m_textControl->SetFont(font);
        m_textControl->SetForegroundColour(colour);
    }
}
 
void MyFrame::OnToggleStatusBar(wxCommandEvent& event)
{
    bool isChecked = m_menuView->IsChecked(ID_StatusBar);
 
    // StatusBar의 보임/숨김 상태를 설정합니다.
    if (m_statusBar) { // m_statusBar가 유효한지 확인합니다.
        m_statusBar->Show(isChecked);
    }
 
    // 프레임의 레이아웃을 갱신하여 m_textControl이 남은 공간을 가득 채우도록 합니다.
    this->Layout();
 
    // 프레임의 크기를 조정하여 내부 컨트롤들이 적절하게 배치되도록 합니다.
    // 이 부분은 필요에 따라 추가하거나 생략할 수 있습니다.
    this->SendSizeEvent();
}
 
// 이벤트 처리 함수 구현
void MyFrame::OnMyCustomEvent(MyCustomEvent& event)
{
    const wxFont info = event.GetwxFont();
 
    int fontSize = info.GetPointSize();
    // 이벤트와 함께 전달된 정보 처리
    m_textControl->SetFont(info);
 
    //textControl->SetFont(font);
    //m_dialog->Destroy(); // dialog를 안전하게 삭제
    //delete m_dialog;
}
cs

 

Posted by JunkMam
,

 NotePad에서 [편집] > [시간/날짜]를 누르면, 메모장에서 시간과 날짜가 추가되는 기능이 있는데.

 그것을 wxWidgets에서 구현하고자한다.

 

 [Edit] > [DateTime] 이런식의 메뉴를 추가하기 위해서 메뉴 정보를 열거형으로 선언한다.

 

 wxMain.h에는 다음과 같이 수정해준다.

1
2
3
4
5
6
7
8
9
10
enum
{
    ID_QUIT,
    ID_SAVE_AS,
    ID_DATETIME,
    ID_WordWarp,
    ID_FontSetting,
    ID_StatusBar,
};
 
cs

 

메뉴바에서 메뉴를 추가하기 위해서 wxMenu 변수를 추가한다.

wxMenu에서 wxMenu* m_menuEdit을 추가한다.

1
2
3
4
5
6
    // 메뉴바 및 메뉴 변수.
    wxMenuBar* m_menuBar;
    wxMenu* m_menuFile;
    wxMenu* m_menuEdit;
    wxMenu* m_menuFormat;
    wxMenu* m_menuView;
cs

 

메뉴가 추가되었으니.

메뉴를 클릭했을때, 동작시키는 이벤트 핸들러를 추가해준다.

OnInsertDateTime(wxCommandEvent& event)을 추가해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    // File 메뉴에 적용할 이벤트 핸들러
    void OnNew(wxCommandEvent& event);
    void OnNewWindow(wxCommandEvent& event);
    void OnOpen(wxCommandEvent& event);
    void OnSave(wxCommandEvent& event);
    void OnSaveAs(wxCommandEvent& event);
    void OnButtonClick(wxCommandEvent& event);
 
    // Edit 메뉴에 적용할 이벤트 핸들러
    void OnInsertDateTime(wxCommandEvent& event);
 
    // Format 메뉴에 적용할 이벤트 핸들러
    void OnToggleWordWrap(wxCommandEvent& event);
    void OnFontSetting(wxCommandEvent& event);
 
    // View 메뉴에 적용할 이벤트 핸들러
    void OnToggleStatusBar(wxCommandEvent& event);
 
    // 이벤트를 받기 위한 메소드
    void OnMyCustomEvent(MyCustomEvent& event);
cs

 

이렇게 wxMain.h로 선언을 제대로 완료했으면, wxMain.cpp에서 선언으로 추가한 코드들을 구현해주자.

 

 wxMain.cpp 에서 Bind로 메뉴에 이벤트 핸들러랑 연결하도록 한다.

1
2
    // 메뉴 Edit에 관련된 이벤트 핸들러
    Bind(wxEVT_MENU, &MyFrame::OnInsertDateTime, this, ID_DATETIME);
cs

 

 이렇게 한 후에 OnInsertDateTime을 구현한다.

1
2
3
4
5
6
7
8
9
void MyFrame::OnInsertDateTime(wxCommandEvent& event) {
    // 현재 날짜와 시간을 가져옴.
    wxDateTime now = wxDateTime::Now();
    // 현재 날짜와 시간을 기본 형식으로 문자열로 변환.
    wxString dateTimeStr = now.Format();
 
    // 현재 텍스트 컨트롤에 날짜와 시간의 문자열을 삽입함.
    m_textControl->AppendText(dateTimeStr);
}
cs

 

 

textControl에서 AppendText을 이용하면, 마지막에 현재 날짜와 시간의 문자열로 삽입하게 된다.

 

현재 위치의 커서에서 출력하도록 할려면, 다음과 같이 수정해야된다.

1
2
3
4
5
6
7
8
9
 
void MyFrame::OnInsertDateTime(wxCommandEvent& event) {
    // 현재 날짜와 시간을 가져옴.
    wxDateTime now = wxDateTime::Now();
    // 현재 날짜와 시간을 기본 형식으로 문자열로 변환.
    wxString dateTimeStr = now.Format();
 
    m_textControl->WriteText(dateTimeStr);
}
cs

 

이렇게 하면, 끝이 아니라 현재 커서에서 해당 문자열이 추가되는걸 확인이 가능하다.

 

 

 

 

 

 

 

 

Posted by JunkMam
,

 이전에 저장 기능에서 파일 경로를 새로 불러오는 경우가 불편해서 뺏다면, 이번엔 다른 이름으로 저장해야되는 경우가 생길 수 있다.

 이걸 구현하기 위해서 메뉴를 추가해줘야한다.

wxMain.h

1
2
3
4
5
6
7
8
enum
{
    ID_QUIT,
    ID_SAVE_AS,
    ID_WordWarp,
    ID_FontSetting,
    ID_StatusBar,
};
cs

 

 

 이렇게 해서 ID을 추가하고,

 

Bind로 연결될 이벤트 핸들러 메소드를 선언해준다.
OnSaveAs을 wxMain.h에 추가해준다.

 

wxMain.h

1
2
3
    void OnOpen(wxCommandEvent& event);
    void OnSave(wxCommandEvent& event);
    void OnSaveAs(wxCommandEvent& event);
cs

 

 

이 후에 wxMain.cpp에서 메뉴를 추가하는 기능을 정의하며, 이벤트 핸들러를 정의 및 연결해줘야한다.

wxMain.cpp

1
2
3
4
5
6
7
8
    m_menuFile = new wxMenu;
    m_menuFile->Append(wxID_NEW, "&New\tCtrl-N""New a Notepad");
    m_menuFile->Append(ID_NEW_WINDOW, "&New Windows\tCtrl+Shift+N""Open a new window.");
    m_menuFile->Append(wxID_OPEN, "&Open\tCtrl-O""Open a file");
    m_menuFile->Append(wxID_SAVE, "&Save\tCtrl-S""Save the file");
    m_menuFile->Append(ID_SAVE_AS, "Save &As\tCtrl-A""Save the file");
    m_menuFile->AppendSeparator();
    m_menuFile->Append(ID_QUIT, "E&xit\tAlt-X""프로그램 종료");
cs

 

이렇게 메뉴를 추가한다.

 Append(ID_SAVE_AS, "Save &As\tCtrl-A", "Save the file");을 이용해서 메뉴를 추가해준다.

 

 이 후에 이벤트 핸들러를 연결해준다.

wxMain.cpp

1
2
3
    Bind(wxEVT_MENU, &MyFrame::OnOpen, this, wxID_OPEN);
    Bind(wxEVT_MENU, &MyFrame::OnSave, this, wxID_SAVE);
    Bind(wxEVT_MENU, &MyFrame::OnSaveAs, this, ID_SAVE_AS);
cs

 

Bind을 이용해서 설정해놓은 ID_SAVE_AS에 연결이 되었으니.

OnSaveAs라는 함수를 정의 해줘야한다.

wxMain.cpp

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
31
32
33
34
35
36
void MyFrame::OnSaveAs(wxCommandEvent& event)
{
    wxFileDialog saveFileDialog(this, _("Save TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
 
    wxString saveAsFileName;
    wxString saveAsFilePath;
 
    switch (saveFileDialog.ShowModal()) {
    case wxID_OK: {
        saveAsFileName = saveFileDialog.GetFilename();
        saveAsFilePath = saveFileDialog.GetPath();
        break;
    }
    case wxID_CANCEL: {
        return;
    }
    }
 
    // 사용자가 선택한 파일 경로를 저장합니다.
    if (!m_textControl->SaveFile(saveAsFilePath))
    {
        wxMessageBox("Could not save the file!""Error", wxOK | wxICON_ERROR);
        return;
    }
 
    // 파일이 성공적으로 저장되었다면, 현재 파일 경로를 업데이트하고 타이틀을 설정합니다.
    m_currentFileName = saveAsFileName;
    m_currentFilePath = saveAsFilePath;
    wxString titleNames = m_currentFileName;
    SetTitle(titleNames + " - Notepad"); // 타이틀 업데이트
 
    // 상태 표시줄에 메시지를 표시합니다.
    SetStatusText("File saved successfully.");
}
 
cs

 

 이렇게 해서 메시지를 표시 및 적용할 수 있게 된다.

 

 

Posted by JunkMam
,

 C언어는 절차적 언어에서 대표적인 언어이다.

 여기서 절차적 언어란, 실행한 동작을 실행하는 것으로 순서에 맞춰서 동작하는 것을 뜻한다.

 

 C언어는 기본적으로 함수로 이루어져 있으며, 함수란 '기능'들을 정의한 것을 뜻한다.

 

 대표적으로 프로그램이 동작하면, 먼저 실행되는 함수로 main이라는 함수가 존재한다.

 그래서 C언어를 먼저 작성할때, 다음과 같은 방식으로 소스가 구성된다.

1
2
3
4
int main(int argc, char** argv){
    return 0;
}
 
cs

 

 여기서 int 는 반환할 데이터의 크기를 뜻하고, main은 함수명, argc는 프로그램이 동작하기 전에 들어오는 명령들의 갯수를 뜻한다. argv는 프로그램이 실행하면서 프로그램에게 준 명령들을 뜻한다.

 return은 프로그램이 종료된 후에 운영체제 혹은 프로그램을 실행한 존재에게 값을 전송하는 것으로 '반환'하는 정보를 뜻한다.

 

 그래서 장치를 실행 시키면, 다음과 같은 창을 만들 수 있다.

 

 

 간단하게 특정 프로그램을 실행 시켜서 값을 나오게 하는 예시를 작성한다면,

1
2
3
4
int main(int argc, char** argv){
    return 1+1;
}
 
cs

 

이렇게 하면, 해당 프로그램을 실행시킨 후 반환되는 값은 1+1로 2라는 값을 반환하게 되며, CMD나 Powershell 같은 프로그램 실행한 개체가 그 값을 받아서 다른 작업을 하는데 사용 할 수 있다.

 

 C언어는 콘솔 환경(명령 프로토콜로 동작하는 Shell 환경에서 동작하는 장치)에 맞춰진 프로그램 언어였다.

 그래서, 요즘과는 익숙하지 않지만, CMD나 PowerShell등 Shell 환경에서 동작하면, 다음과 같이 작업이 가능하다.

 예시로

 PowerShell에서 적용한 예시.

 

 이렇게 해서 반환해서 출력한 후에 결과물을 보고 다음 작업을 할 수 있게 한다.

 

 내부에서 함수를 다양하게 만들어서 동작시키면 되기 때문에 이렇게 단순하게 적용하진 않지만, return에 0을 맞춰서 반환하도록 한다.

 이유는 컴퓨터에서 해당 프로그램을 실행한 대상자가 프로그램이 이상없이 종료가 되었는지 확인하여 대처하기 위함이다.

 

 argc는 'argument count'라는 것으로 프로그램이 실행할때 shell에 적용한 명령어들의 갯수를 세는 것으로 프로그램을 실행한 C_Base.exe라는 전달인자 1개가 무조건 들어가기 때문에 값이 1 이상이된다.

1
2
3
4
5
int main(int argc, char** argv)
{
    return argc;
}
 
cs

 

 

 이렇게 된다.

 

 argument를 더 넣는다면, 다음과 같다.

 

 ※ 여기서 argument의 갯수를 찾기 위해서 'Start-Process'라는 명령어를 사용하고 있지만, 원래는 '.\C_Base.exe a b c' 이런식의 명령을 줬을때 반환값이 저런식으로 들어간다는 것이다.

 

 argv는 'argument values' 전달 인자들의 값을 저장한다.

 이걸 간단하게 테스트하기 위해선 문자열을 반환하는 것보단 #include <stdio.h>[Standard IO Header File]을 이용해서 간단하게 출력을 해서 확인 할 수 있다.

 

 ※ Standard IO는 C언어를 제작한 개발 측에서 제공해주는 출력 및 입력에 관련된 함수들을 저장한 헤더 파일이다.

 

 다음과 같이 작성해서 확인이 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int main(int argc, char** argv)
{
    int argcLoop = 0;
    printf("argc: %d\n", argc);
 
    for(argcLoop = 0; argcLoop < argc; ++argcLoop){
        printf("argv - %d: %s", argcLoop+1, argv[argcLoop]);
    }
 
    return 0;
}
 
cs

 

이 코드는 argument[전달인자]의 값을 받아서 몇 번째에 어떤 전달 인자가 들어가 있는지 출력하는 코드이다.

이 코드로 만든 프로그램을 인자 없이 실행 시켜보면,

 

 이렇게 실행 프로그램에 관련된 경로가 전달 인자에 들어가 있는걸 알 수 있다.

 이후에 더 많은 인자를 넣으면 다음과 같이 출력이 되는걸 확인 할 수 있다.

 

 띄워쓰기나 줄 바꿈을 넣지 않은 상태여서 확인을 하기 어려움이 있지만,

 argv - 을 기준으로 나눠서 보면, Shell에서 프로그램을 실행하기 전에 전달한 인자들이 출력되는걸 확인 할 수 있다.

 

 여기서 shell 명령까지 연결해서 작업을 하면,

 

 이렇게 Shell에게 특정 인자를 받아서 프로그램을 동작시키는 기능 등을 제작 할 수 있다.

'프로그래밍 > C 언어' 카테고리의 다른 글

[C] 제어(1) - 조건문 -  (0) 2024.02.17
[C] 연산자  (0) 2024.02.16
[C] 상수와 변수  (0) 2024.02.15
[C] 기본적으로 지원해주는 출력  (0) 2024.02.14
Posted by JunkMam
,

연습4

카테고리 없음 2024. 2. 13. 00:00

ㅇㄻㄹㅇㅈㅂㄷㄱ

Posted by JunkMam
,

 wxWidgets에서 열거나 저장한 후에 파일에서 저장을 매번 경로를 지정해줘야하는 문제점이 있다.

 이 점을 개선하기 위해서 저장의 경로를 저장해놓아야 되는 경우가 생긴다.

 경로를 저장하기 위해서 wxMain.h을 다음과 같이 수정한다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#pragma once
#include "wx/wx.h"
#include <wx/filedlg.h>
#include <wx/textctrl.h>
#include <wx/splitter.h>
 
// Font Dialog
#include <wx/fontdlg.h>
 
// 파일을 읽어 들이기 위한 용도.
#include <fstream>
#include <sstream>
 
#include "wxOptionsDialog.h"
 
enum
{
    ID_QUIT,
    ID_WordWarp,
    ID_FontSetting,
    ID_StatusBar,
};
 
enum {
    MY_EVENT_ID = 10001,
};
 
// 메뉴 항목 ID 정의
enum
{
    ID_NEW_WINDOW = wxID_HIGHEST + 1 // 새 창을 위한 고유 ID
};
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title);
 
    void OnQuit(wxCommandEvent& event);
 
private:
    wxTextCtrl* m_textControl;
 
    // 현재 파일의 경로를 저장하는 변수
    wxString m_currentFileName;
    wxString m_currentFilePath;
 
 
    //wxOptionDialog* m_dialog;
    wxFont* m_font;
 
    wxStatusBar* m_statusBar;
 
    // 메뉴바 및 메뉴 변수.
    wxMenuBar* m_menuBar;
    wxMenu* m_menuFile;
    wxMenu* m_menuFormat;
    wxMenu* m_menuView;
 
    void OnNew(wxCommandEvent& event);
    void OnNewWindow(wxCommandEvent& event);
    void OnOpen(wxCommandEvent& event);
    void OnSave(wxCommandEvent& event);
    void OnButtonClick(wxCommandEvent& event);
 
    // Format 메뉴에 적용할 이벤트 핸들러
    void OnToggleWordWrap(wxCommandEvent& event);
    void OnFontSetting(wxCommandEvent& event);
 
    // View 메뉴에 적용할 이벤트 핸들러
    void OnToggleStatusBar(wxCommandEvent& event);
 
 
    // 이벤트를 받기 위한 메소드
    void OnMyCustomEvent(MyCustomEvent& event);
};
 
cs

 

 여기서 열어둔 파일들의 경로와 이름을 저장하기 위해서

 wxString m_currentFileName; // 현재 파일 이름

 wxString m_currentFilePath; // 현재 파일 경로

 

 이 2개를 추가했다.

 

 이 후에 wxMain.cpp에 있는 OnSave이라는 이벤트 핸들러를 다음과 같이 수정한다.

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
31
32
33
34
35
 
void MyFrame::OnSave(wxCommandEvent& event)
{
    wxFileDialog saveFileDialog(this, _("Save TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
 
    // 경로가 비어있는 경우엔.
    if (m_currentFilePath.IsEmpty()) {
        switch (saveFileDialog.ShowModal()) {
        case wxID_CANCEL: {
            return;
        }
 
        case wxID_OK: {
            m_currentFileName = saveFileDialog.GetFilename();
            // 세이브 및 적용이 완료했을 경우.
            m_currentFilePath = saveFileDialog.GetPath();
            break;
        }
        }
    }
 
    // 현재 텍스트 컨트롤의 내용을 파일에 저장합니다.
    if (!m_textControl->SaveFile(m_currentFilePath)) {
        // 현재 텍스트의 내용을 파일에 저장하지 못한다면.
        wxMessageBox("Could Not save the File!""Error", wxOK);
        return;
    }
 
    wxString titleNames = m_currentFileName;
    titleNames += " - Notepad";
    // 타이틀을 열린 파일의 이름으로 설정합니다.
    SetTitle(titleNames);
}
 
cs

 

 m_currentFilePath의 내용이 비어 있다면, 저장 경로를 받기 위해서 saveFileDialog.ShowModel을 하여, 경로를 제공 받게 한다.

 OK을 눌렀을 경우에 saveFileDialog에 파일 이름과 파일 경로를 각각 m_currentFileName과 m_currentFilePath에 저장하도록 한다.

 저장이 실패했을 경우엔 제대로 파일에 저장을 하지 못했다는 정보를 알려준다.

 여기서 실패했을 경우에 다시 경로를 찾아 가야도록 해야되므로

 

 지역 변수를 이용해서 적용하는 방법도 있다.

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
31
32
33
34
35
36
37
38
39
40
41
 
void MyFrame::OnSave(wxCommandEvent& event)
{
    wxFileDialog saveFileDialog(this, _("Save TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
 
    wxString saveFileName = m_currentFileName;
    wxString saveFilePath = m_currentFilePath;
 
    // 경로가 비어있는 경우엔.
    if (m_currentFilePath.IsEmpty()) {
        switch (saveFileDialog.ShowModal()) {
        case wxID_CANCEL: {
            return;
        }
 
        case wxID_OK: {
            saveFileName = saveFileDialog.GetFilename();
            // 세이브 및 적용이 완료했을 경우.
            saveFilePath = saveFileDialog.GetPath();
            break;
        }
        }
    }
 
    // 현재 텍스트 컨트롤의 내용을 파일에 저장합니다.
    if (!m_textControl->SaveFile(saveFilePath)) {
        // 현재 텍스트의 내용을 파일에 저장하지 못한다면.
        wxMessageBox("Could Not save the File!""Error", wxOK);
        return;
    }
 
    m_currentFileName = saveFileName;
    m_currentFilePath = saveFilePath;
 
    wxString titleNames = m_currentFileName;
    titleNames += " - Notepad";
    // 타이틀을 열린 파일의 이름으로 설정합니다.
    SetTitle(titleNames);
}
 
cs

 

 이 후에 Open을 했을 경우에 작동할 이벤트 핸들러를 적용해야한다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
void MyFrame::OnOpen(wxCommandEvent& event)
{
    wxFileDialog openFileDialog(this, _("Open TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
 
    wxString openFileName = m_currentFileName;
    wxString openFilePath = m_currentFilePath;
 
    switch (openFileDialog.ShowModal()) {
    case wxID_OK: {
        openFileName = openFileDialog.GetFilename();
        // 세이브 및 적용이 완료했을 경우.
        openFilePath = openFileDialog.GetPath();
        break;
    }
    case wxID_CANCEL: {
        return// 사용자가 취소했을 때
    }
    }
 
    std::ifstream file(openFilePath.ToStdString());
    // 파일을 열고 텍스트 컨트롤에 내용을 로드합니다.
    if (m_textControl->LoadFile(openFilePath)) {
        std::stringstream buffer;
        buffer << file.rdbuf(); // 파일의 내용을 buffer에 읽어 들입니다.
        file.close(); // 파일을 닫습니다.
 
        // textControl의 내용을 갱신합니다.
        m_textControl->SetValue(buffer.str());
        //textControl->SetLabelText(buffer.str());
        m_currentFileName = openFileName;
        m_currentFilePath = openFilePath;
        
        wxString titleNames = m_currentFileName;
        titleNames += " - Notepad";
        // 타이틀을 열린 파일의 이름으로 설정합니다.
        SetTitle(titleNames);
 
    }
    else {
        wxMessageBox("Cannot open File!""Error", wxOK | wxICON_ERROR);
    }
}
cs

 

 이렇게 하면, 열었을때, 저장을 바로 적용할 수 있고,

 저장 경로를 정했을 경우에 약간 수정하고 바로 저장을 누르면 적용이 가능해진다.

 

Posted by JunkMam
,

 View라는 메뉴를 추가하여 StatusBar를 On/Off하는 기능을 적용하기 위해서 다음과 같이 한다.

 

 wxMain.h

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#pragma once
#include "wx/wx.h"
#include <wx/filedlg.h>
#include <wx/textctrl.h>
#include <wx/splitter.h>
 
// Font Dialog
#include <wx/fontdlg.h>
 
// 파일을 읽어 들이기 위한 용도.
#include <fstream>
#include <sstream>
 
#include "wxOptionsDialog.h"
 
enum
{
    ID_QUIT,
    ID_WordWarp,
    ID_FontSetting,
    ID_StatusBar,
};
 
enum {
    MY_EVENT_ID = 10001,
};
 
// 메뉴 항목 ID 정의
enum
{
    ID_NEW_WINDOW = wxID_HIGHEST + 1 // 새 창을 위한 고유 ID
};
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title);
 
    void OnQuit(wxCommandEvent& event);
 
private:
    wxTextCtrl* m_textControl;
    //wxOptionDialog* m_dialog;
    wxFont* m_font;
 
    wxStatusBar* m_statusBar;
 
    // 메뉴바 및 메뉴 변수.
    wxMenuBar* m_menuBar;
    wxMenu* m_menuFile;
    wxMenu* m_menuFormat;
    wxMenu* m_menuView;
 
    void OnNew(wxCommandEvent& event);
    void OnNewWindow(wxCommandEvent& event);
    void OnOpen(wxCommandEvent& event);
    void OnSave(wxCommandEvent& event);
    void OnButtonClick(wxCommandEvent& event);
 
    // Format 메뉴에 적용할 이벤트 핸들러
    void OnToggleWordWrap(wxCommandEvent& event);
    void OnFontSetting(wxCommandEvent& event);
 
    // View 메뉴에 적용할 이벤트 핸들러
    void OnToggleStatusBar(wxCommandEvent& event);
 
 
    // 이벤트를 받기 위한 메소드
    void OnMyCustomEvent(MyCustomEvent& event);
};
 
cs

 

 여기서 추가 된것은

 m_statusBar이다.

 m_statusBar를 이용해서 상태바를 보이고, 보이지 않게 할 수 있다.

 

 wxMain.cpp

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#include "wxMain.h"
 
wxIMPLEMENT_APP(MyApp);
 
bool MyApp::OnInit()
{
    MyFrame* frame = new MyFrame("No Title - Notepad");
    frame->Show(true);
    return true;
}
 
MyFrame::MyFrame(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title)
{
    m_menuFile = new wxMenu;
    m_menuFile->Append(wxID_NEW, "&New\tCtrl-N""New a Notepad");
    m_menuFile->Append(ID_NEW_WINDOW, "&New Windows\tCtrl+Shift+N""Open a new window.");
    m_menuFile->Append(wxID_OPEN, "&Open\tCtrl-O""Open a file");
    m_menuFile->Append(wxID_SAVE, "&Save\tCtrl-S""Save the file");
    m_menuFile->AppendSeparator();
    m_menuFile->Append(ID_QUIT, "E&xit\tAlt-X""프로그램 종료");
 
    m_menuFormat = new wxMenu;
    m_menuFormat->AppendCheckItem(ID_WordWarp, "Word &Wrap\tCtrl+W""Toggle word wrapping.");
    m_menuFormat->Append(ID_FontSetting, "&Font""Font Set Menu");
 
    m_menuView = new wxMenu;
    m_menuView->AppendCheckItem(ID_StatusBar, "Show &StatusBar""Toggle Status Bar.");
    
    m_menuBar = new wxMenuBar;
    m_menuBar->Append(m_menuFile, "&File");
    m_menuBar->Append(m_menuFormat, "F&omat");
    m_menuBar->Append(m_menuView, "&View");
 
    SetMenuBar(m_menuBar);
 
    m_textControl = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
 
    // sizer를 생성하여 텍스트 컨트롤의 크기를 조정합니다.
    wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
    sizer->Add(m_textControl, 1, wxEXPAND | wxALL, 0); // wxEXPAND는 컨트롤이 sizer의 가능한 모든 공간을 차지하도록 합니다. 1은 비율을 의미하며, 이 경우 다른 컨트롤이 없으므로 전체 크기를 차지합니다.
 
    // 프레임에 sizer를 설정합니다.
    this->SetSizer(sizer);
    this->Layout(); // sizer를 강제로 다시 계산하여 적용합니다.
 
    // 폰트 설정
    wxFont font(16, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
    m_textControl->SetFont(font);
 
    //m_statusBar = new wxStatusBar(this);
    m_statusBar = CreateStatusBar();
    SetStatusText("Ready");
    // ID_StatusBar 메뉴 항목을 자동으로 체크되어 있도록 설정
    m_menuView->Check(ID_StatusBar, true);
 
    // 이벤트 핸들러 연결
    Bind(wxEVT_MENU, &MyFrame::OnNew, this, wxID_NEW);
 
    // MyFrame 생성자 또는 초기화 함수 내
    Bind(wxEVT_MENU, &MyFrame::OnNewWindow, this, ID_NEW_WINDOW);
 
    Bind(wxEVT_MENU, &MyFrame::OnOpen, this, wxID_OPEN);
    Bind(wxEVT_MENU, &MyFrame::OnSave, this, wxID_SAVE);
 
    Bind(wxEVT_MENU, &MyFrame::OnQuit, this, ID_QUIT);
 
    // 메뉴 Format에 관련된 이벤트 핸들러
    Bind(wxEVT_MENU, &MyFrame::OnToggleWordWrap, this, ID_WordWarp);
    Bind(wxEVT_MENU, &MyFrame::OnFontSetting, this, ID_FontSetting);
 
    // 메뉴 View에 관련된 이벤트 핸들러
    Bind(wxEVT_MENU, &MyFrame::OnToggleStatusBar, this, ID_StatusBar);
 
    // 이벤트 처리기 등록
    Bind(MY_CUSTOM_EVENT, &MyFrame::OnMyCustomEvent, this);
}
 
void MyFrame::OnQuit(wxCommandEvent& event)
{
    Close(true);
}
 
void MyFrame::OnNew(wxCommandEvent& event) {
    // 텍스트 컨트롤의 내용을 비웁니다.
    m_textControl->Clear();
 
    // 타이틀에 메시지를 새로 작성합니다.
    wxString titleNames = "No Title";
    titleNames += " - Notepad";
    SetTitle(titleNames);
 
    // 상태 표시줄에 메시지를 표시합니다.
    SetStatusText("New document created.");
}
 
// MyFrame 클래스 내
void MyFrame::OnNewWindow(wxCommandEvent& event)
{
    // 새로운 창을 생성하고 표시
    MyFrame* newFrame = new MyFrame("No Title - Notepad");
    newFrame->Show(true);
}
 
void MyFrame::OnOpen(wxCommandEvent& event)
{
    wxFileDialog openFileDialog(this, _("Open TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
    if (openFileDialog.ShowModal() == wxID_CANCEL)
        return// 사용자가 취소했을 때
 
    std::ifstream file(openFileDialog.GetPath().ToStdString());
    // 파일을 열고 텍스트 컨트롤에 내용을 로드합니다.
    if (m_textControl->LoadFile(openFileDialog.GetPath())) {
        std::stringstream buffer;
        buffer << file.rdbuf(); // 파일의 내용을 buffer에 읽어 들입니다.
        file.close(); // 파일을 닫습니다.
 
        // textControl의 내용을 갱신합니다.
        m_textControl->SetValue(buffer.str());
        //textControl->SetLabelText(buffer.str());
        
        wxString titleNames = openFileDialog.GetFilename();
        titleNames += " - Notepad";
        // 타이틀을 열린 파일의 이름으로 설정합니다.
        SetTitle(titleNames);
 
    }
    else {
        wxMessageBox("Cannot open File!""Error", wxOK | wxICON_ERROR);
    }
}
 
void MyFrame::OnSave(wxCommandEvent& event)
{
    wxFileDialog saveFileDialog(this, _("Save TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
    if (saveFileDialog.ShowModal() == wxID_CANCEL)
        return// 사용자가 취소했을 때
 
    // 현재 텍스트 컨트롤의 내용을 파일에 저장합니다.
    m_textControl->SaveFile(saveFileDialog.GetPath());
 
    wxString titleNames = saveFileDialog.GetFilename();
    titleNames += " - Notepad";
    // 타이틀을 열린 파일의 이름으로 설정합니다.
    SetTitle(titleNames);
}
 
void MyFrame::OnToggleWordWrap(wxCommandEvent& event)
{
    bool isChecked = m_menuFormat->IsChecked(ID_WordWarp);
    m_textControl->SetWindowStyleFlag(isChecked ? (m_textControl->GetWindowStyleFlag() | wxTE_WORDWRAP) : (m_textControl->GetWindowStyleFlag() & ~wxTE_WORDWRAP));
    m_textControl->Refresh(); // 화면 갱신
}
 
void MyFrame::OnFontSetting(wxCommandEvent& event)
{
    /*dialog = new wxOptionDialog(this, wxID_ANY, "Settings");
    dialog->ShowModal();*/
 
    wxFontData fontData;
    fontData.SetInitialFont(m_textControl->GetFont());
    fontData.SetColour(m_textControl->GetForegroundColour());
 
    wxFontDialog fontDialog(this, fontData);
    if (fontDialog.ShowModal() == wxID_OK)
    {
        wxFontData retData = fontDialog.GetFontData();
        wxFont font = retData.GetChosenFont();
        wxColour colour = retData.GetColour();
 
        m_textControl->SetFont(font);
        m_textControl->SetForegroundColour(colour);
    }
}
 
void MyFrame::OnToggleStatusBar(wxCommandEvent& event)
{
    bool isChecked = m_menuView->IsChecked(ID_StatusBar);
 
    // StatusBar의 보임/숨김 상태를 설정합니다.
    if (m_statusBar) { // m_statusBar가 유효한지 확인합니다.
        m_statusBar->Show(isChecked);
    }
 
    // 프레임의 레이아웃을 갱신하여 m_textControl이 남은 공간을 가득 채우도록 합니다.
    this->Layout();
 
    // 프레임의 크기를 조정하여 내부 컨트롤들이 적절하게 배치되도록 합니다.
    // 이 부분은 필요에 따라 추가하거나 생략할 수 있습니다.
    this->SendSizeEvent();
}
 
// 이벤트 처리 함수 구현
void MyFrame::OnMyCustomEvent(MyCustomEvent& event)
{
    const wxFont info = event.GetwxFont();
 
    int fontSize = info.GetPointSize();
    // 이벤트와 함께 전달된 정보 처리
    m_textControl->SetFont(info);
 
    //textControl->SetFont(font);
    //m_dialog->Destroy(); // dialog를 안전하게 삭제
    //delete m_dialog;
}
cs

 

 CreateStatusBar()는 wxStatusBar라는 클래스를 반환한다. 그래서, m_statusBar에 저장하면, 컨트롤하기 편해진다.

1
    m_statusBar = CreateStatusBar();
cs

 

View 메뉴에서 StatusBar를 컨트롤하기 위해서 이벤트 핸들러를 적용한다.

1
2
3
 
    // 메뉴 View에 관련된 이벤트 핸들러
    Bind(wxEVT_MENU, &MyFrame::OnToggleStatusBar, this, ID_StatusBar);
cs

 

 메뉴 이벤트 핸들러 및 Check을 컨트롤하기 위해서

 ID_StatusBar라는 열거형을 작성해줘야한다.

1
2
3
4
5
6
7
8
9
 
enum
{
    ID_QUIT,
    ID_WordWarp,
    ID_FontSetting,
    ID_StatusBar,
};
 
cs

 

이제, 이벤트 핸들러인 OnToggleStatusBar을 구현한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
void MyFrame::OnToggleStatusBar(wxCommandEvent& event)
{
    bool isChecked = m_menuView->IsChecked(ID_StatusBar);
 
    // StatusBar의 보임/숨김 상태를 설정합니다.
    if (m_statusBar) { // m_statusBar가 유효한지 확인합니다.
        m_statusBar->Show(isChecked);
    }
 
    // 프레임의 레이아웃을 갱신하여 m_textControl이 남은 공간을 가득 채우도록 합니다.
    this->Layout();
 
    // 프레임의 크기를 조정하여 내부 컨트롤들이 적절하게 배치되도록 합니다.
    // 이 부분은 필요에 따라 추가하거나 생략할 수 있습니다.
    this->SendSizeEvent();
}
 
cs

 

 이렇게 하면, StatusBar가 보여지는거와 보이지 않는 것에 따라서 TextCtrl의 크기를 재정의 하여 비어지는 경우가 없어진다.

 

 여기서 CheckItem들은 기본이 Checked가 false인 상태이다.

 그래서 강제로 Checked true로 설정해준다면, 'm_menuView->Check(ID_StatusBar, true);'을 추가해주면 된다.

 

Posted by JunkMam
,

 wxMain에서 새 창을 만들면서 새 창을 띄우는 방식으로 개별로 윈도우를 만들어서 작업 할 수 있는 기능이다.

 

 wxMain.h

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#pragma once
#include "wx/wx.h"
#include <wx/filedlg.h>
#include <wx/textctrl.h>
#include <wx/splitter.h>
 
// Font Dialog
#include <wx/fontdlg.h>
 
// 파일을 읽어 들이기 위한 용도.
#include <fstream>
#include <sstream>
 
#include "wxOptionsDialog.h"
 
enum
{
    ID_QUIT,
    ID_WORD_WRAP,
    ID_FontSetting,
};
 
enum {
    MY_EVENT_ID = 10001,
};
 
// 메뉴 항목 ID 정의
enum
{
    ID_NEW_WINDOW = wxID_HIGHEST + 1 // 새 창을 위한 고유 ID
};
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title);
 
    void OnQuit(wxCommandEvent& event);
 
private:
    wxTextCtrl* textControl;
    wxOptionDialog* dialog;
    wxFont* font;
 
    // 메뉴바 및 메뉴 변수.
    wxMenuBar* menuBar;
    wxMenu* menuFile;
    wxMenu* menuFormat;
 
    void OnNew(wxCommandEvent& event);
    void OnNewWindow(wxCommandEvent& event);
    void OnOpen(wxCommandEvent& event);
    void OnSave(wxCommandEvent& event);
    void OnButtonClick(wxCommandEvent& event);
 
    // 세팅 창을 띄우기 위한 메소드
    void OnToggleWordWrap(wxCommandEvent& event);
    void OnFontSetting(wxCommandEvent& event);
 
    // 이벤트를 받기 위한 메소드
    void OnMyCustomEvent(MyCustomEvent& event);
};
 
cs

 

 wxMain.cpp

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include "wxMain.h"
 
wxIMPLEMENT_APP(MyApp);
 
bool MyApp::OnInit()
{
    MyFrame* frame = new MyFrame("No Title - Notepad");
    frame->Show(true);
    return true;
}
 
MyFrame::MyFrame(const wxString& title)
    : wxFrame(NULL, wxID_ANY, title)
{
    menuFile = new wxMenu;
    menuFile->Append(wxID_NEW, "&New\tCtrl-N""New a Notepad");
    menuFile->Append(ID_NEW_WINDOW, "&New Windows\tCtrl+Shift+N""Open a new window.");
    menuFile->Append(wxID_OPEN, "&Open\tCtrl-O""Open a file");
    menuFile->Append(wxID_SAVE, "&Save\tCtrl-S""Save the file");
    menuFile->AppendSeparator();
    menuFile->Append(ID_QUIT, "E&xit\tAlt-X""프로그램 종료");
 
    menuFormat = new wxMenu;
    menuFormat->AppendCheckItem(ID_WORD_WRAP, "Word &Wrap\tCtrl+W""Toggle word wrapping.");
    menuFormat->Append(ID_FontSetting, "&Font""Font Set Menu");
    
 
    menuBar = new wxMenuBar;
    menuBar->Append(menuFile, "&File");
    menuBar->Append(menuFormat, "&F&omat");
 
    SetMenuBar(menuBar);
 
    textControl = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
 
    // sizer를 생성하여 텍스트 컨트롤의 크기를 조정합니다.
    wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
    sizer->Add(textControl, 1, wxEXPAND | wxALL, 0); // wxEXPAND는 컨트롤이 sizer의 가능한 모든 공간을 차지하도록 합니다. 1은 비율을 의미하며, 이 경우 다른 컨트롤이 없으므로 전체 크기를 차지합니다.
 
    // 프레임에 sizer를 설정합니다.
    this->SetSizer(sizer);
    this->Layout(); // sizer를 강제로 다시 계산하여 적용합니다.
 
    // 폰트 설정
    wxFont font(16, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
    textControl->SetFont(font);
 
    CreateStatusBar();
    SetStatusText("Ready");
 
    // 이벤트 핸들러 연결
    Bind(wxEVT_MENU, &MyFrame::OnNew, this, wxID_NEW);
 
    // MyFrame 생성자 또는 초기화 함수 내
    Bind(wxEVT_MENU, &MyFrame::OnNewWindow, this, ID_NEW_WINDOW);
 
    Bind(wxEVT_MENU, &MyFrame::OnOpen, this, wxID_OPEN);
    Bind(wxEVT_MENU, &MyFrame::OnSave, this, wxID_SAVE);
 
    Bind(wxEVT_MENU, &MyFrame::OnQuit, this, ID_QUIT);
 
    // 메뉴 Format에 관련된 이벤트 핸들러
    Bind(wxEVT_MENU, &MyFrame::OnToggleWordWrap, this, ID_WORD_WRAP);
    Bind(wxEVT_MENU, &MyFrame::OnFontSetting, this, ID_FontSetting);
 
    // 이벤트 처리기 등록
    Bind(MY_CUSTOM_EVENT, &MyFrame::OnMyCustomEvent, this);
}
 
void MyFrame::OnQuit(wxCommandEvent& event)
{
    Close(true);
}
 
void MyFrame::OnNew(wxCommandEvent& event) {
    // 텍스트 컨트롤의 내용을 비웁니다.
    textControl->Clear();
 
    // 타이틀에 메시지를 새로 작성합니다.
    wxString titleNames = "No Title";
    titleNames += " - Notepad";
    SetTitle(titleNames);
 
    // 상태 표시줄에 메시지를 표시합니다.
    SetStatusText("New document created.");
}
 
// MyFrame 클래스 내
void MyFrame::OnNewWindow(wxCommandEvent& event)
{
    // 새로운 창을 생성하고 표시
    MyFrame* newFrame = new MyFrame("No Title - Notepad");
    newFrame->Show(true);
}
 
void MyFrame::OnOpen(wxCommandEvent& event)
{
    wxFileDialog openFileDialog(this, _("Open TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
    if (openFileDialog.ShowModal() == wxID_CANCEL)
        return// 사용자가 취소했을 때
 
    std::ifstream file(openFileDialog.GetPath().ToStdString());
    // 파일을 열고 텍스트 컨트롤에 내용을 로드합니다.
    if (textControl->LoadFile(openFileDialog.GetPath())) {
        std::stringstream buffer;
        buffer << file.rdbuf(); // 파일의 내용을 buffer에 읽어 들입니다.
        file.close(); // 파일을 닫습니다.
 
        // textControl의 내용을 갱신합니다.
        textControl->SetValue(buffer.str());
        //textControl->SetLabelText(buffer.str());
        
        wxString titleNames = openFileDialog.GetFilename();
        titleNames += " - Notepad";
        // 타이틀을 열린 파일의 이름으로 설정합니다.
        SetTitle(titleNames);
 
    }
    else {
        wxMessageBox("Cannot open File!""Error", wxOK | wxICON_ERROR);
    }
}
 
void MyFrame::OnSave(wxCommandEvent& event)
{
    wxFileDialog saveFileDialog(this, _("Save TXT file"), """",
        "TXT files (*.txt)|*.txt", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
    if (saveFileDialog.ShowModal() == wxID_CANCEL)
        return// 사용자가 취소했을 때
 
    // 현재 텍스트 컨트롤의 내용을 파일에 저장합니다.
    textControl->SaveFile(saveFileDialog.GetPath());
 
    wxString titleNames = saveFileDialog.GetFilename();
    titleNames += " - Notepad";
    // 타이틀을 열린 파일의 이름으로 설정합니다.
    SetTitle(titleNames);
}
 
void MyFrame::OnToggleWordWrap(wxCommandEvent& event)
{
    bool isChecked = menuFormat->IsChecked(ID_WORD_WRAP);
    textControl->SetWindowStyleFlag(isChecked ? (textControl->GetWindowStyleFlag() | wxTE_WORDWRAP) : (textControl->GetWindowStyleFlag() & ~wxTE_WORDWRAP));
    textControl->Refresh(); // 화면 갱신
}
 
void MyFrame::OnFontSetting(wxCommandEvent& event)
{
    /*dialog = new wxOptionDialog(this, wxID_ANY, "Settings");
    dialog->ShowModal();*/
 
    wxFontData fontData;
    fontData.SetInitialFont(textControl->GetFont());
    fontData.SetColour(textControl->GetForegroundColour());
 
    wxFontDialog fontDialog(this, fontData);
    if (fontDialog.ShowModal() == wxID_OK)
    {
        wxFontData retData = fontDialog.GetFontData();
        wxFont font = retData.GetChosenFont();
        wxColour colour = retData.GetColour();
 
        textControl->SetFont(font);
        textControl->SetForegroundColour(colour);
    }
}
 
// 이벤트 처리 함수 구현
void MyFrame::OnMyCustomEvent(MyCustomEvent& event)
{
    const wxFont info = event.GetwxFont();
 
    int fontSize = info.GetPointSize();
    // 이벤트와 함께 전달된 정보 처리
    textControl->SetFont(info);
 
    //textControl->SetFont(font);
    dialog->Destroy(); // dialog를 안전하게 삭제
    delete dialog;
}
cs

 

 이렇게 하면, Ctrl+Shift+N을 눌을때마다 새 창을 띄우는게 가능해진다.

Posted by JunkMam
,