'2024/02/13'에 해당되는 글 4건

  1. 2024.02.13 [wxWidgets] 다른 이름으로 저장 기능 구현 1
  2. 2024.02.13 [C] 기본 구조 1
  3. 2024.02.13 연습4
  4. 2024.02.13 [wxWidgets] 저장과 열기를 개선하기 1

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

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

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
,