自己動手打造屬於自己的C語言IDE
建議:建議先觀看功能演示,然後根據功能演示想想思路,然後看博文中的思路,最後再看博文代碼,最後再看完整代碼,這樣效果會更好。
功能介紹:一款基於QT的簡易c語言編輯器,可以編輯,編譯和運行。
環境配置:編譯運行功能的前提是windows平臺上已經安裝gcc
並配置到系統環境變量中,這個的配置方式可自行百度,很多帖子有講。或直接安裝QT,便於閱讀源碼。同時,安裝QT自帶會安裝gcc
,將其配置到環境變量中即可
UI
在創建工程的時候勾選上UI選項,會自動生成一個mainWindow
,在菜單欄中點擊添加菜單功能,然後在ui文件中通過拖拽控件佈局。佈局完成後,在佈局下方找到對應控件名稱並右鍵轉到槽,工程會自動在mainwindow.cpp
中生成對應的槽函數,在槽函數中即可實現各自功能。槽函數的命名爲on_action控件名_triggered
。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FHhevjxk-1587451488157)(D:…/configImages/QT_UI.png)]
主要功能實現
打開文件
思路:通過QFileDialog::getOpenFileName()
函數獲取文件路徑。然後通過fopen
打開路徑對應的文件,並通過一個臨時變量str
存放文件中的內容,最後通過ui->textEdit->setText()
函數將臨時變量中的內容展示在文本編輯控件中。最後關閉文件。
注意:通過QFileDialog::getOpenFileName()
函數獲取的文件路徑是QString
類型的數據,所以在給fopen
使用前需要轉換爲char *
類型。QT
中使用UTF-8
編碼,所以如果文件使用GBK
編碼,需要轉換編碼方式。
API
說明:
QFileDialog::getOpenFileName()
通過可視化方式獲取路徑codec->fromUnicode(path).data()
改變編碼方式並轉換數據類型codec->toUnicode(buf)
轉換爲UTF-8
編碼ui->textEdit->setText(str)
向文本編輯框放入待編輯內容
代碼實現:
void MainWindow::on_actionOPEN_triggered()
{
// 打開文件,獲取文件路徑
path = QFileDialog::getOpenFileName();
cout << "path=" << path;
if(path.isEmpty())
{
// 沒有選擇路徑直接退出
return;
}
// 字符編碼轉換
char *fileName = codec->fromUnicode(path).data();
// 打開文件並讀取內容,並放進編輯區
FILE *fp = fopen(fileName, "rb");
if(fp == NULL)
{
cout << "on_actionOPEN_triggered() fopen err";
return;
}
char buf[1024*5];
QString str = "";
// 讀取文件
while (1) {
memset(buf, 0, sizeof (buf));
fgets(buf, sizeof (buf), fp);
// 根據標誌位改變字符編碼方式
if(flag == utf_8)
{
str += buf;
}
else if(flag == GBK)
{
str += codec->toUnicode(buf);
}
if(feof(fp))
{
break;
}
}
// 將文件內容放進編輯區
ui->textEdit->setText(str);
// 關閉文件
fclose(fp);
fp = NULL;
}
文件另存爲
思路:通過QFileDialog::getSaveFileName()
獲取文件待保存的路徑,然後通過臨時變量保存文本編輯區的內容,最後通過寫的方式打開待保存的路徑,將臨時變量內容寫入,關閉文件即可。
注意:依舊是編碼方式,還有QString
和char *
類型的不同
API
說明:
QFileDialog::getSaveFileName()
通過可視化方式獲取保存路徑str.toStdString().data()
將QString
轉換爲char * 類型ui->textEdit->toPlainText()
獲取文本編輯框內容
代碼實現:
void MainWindow::on_actionSAVE_AS_triggered()
{
// 選擇另存爲的路徑,爲UTF8編碼,返回類型爲QString類型
path = QFileDialog::getSaveFileName();
if(path.isEmpty())
{
// 如果沒有選擇路徑直接退出
return;
}
// 需要將路徑轉換爲GBK編碼,並且爲char * 類型
const char *fileName = codec->fromUnicode(path).data();
cout << fileName;
// 打開文件並讀取內容,並放進編輯區
FILE *fp = fopen(fileName, "wb");
if(fp == NULL)
{
cout << "on_actionSAVE_AS_triggered open file err";
}
// 獲取編輯區的內容,返回QString
QString str = ui->textEdit->toPlainText();
// 將QString轉換爲char * 類型
const char *buf = str.toStdString().data();
fputs(buf, fp);
// 關閉文件
fclose(fp);
}
文件保存
思路:如果是open一個文件改動後需要保存,那麼在open的時候就已經獲取到了文件路徑,直接將編輯區的內容獲取後保存到指定文件中即可。如果打開編輯器後開始編輯內容需要保存,那麼此時沒有獲取過路徑,就需要通過QFileDialog::getSaveFileName()
獲取一下保存路徑。
注意:依舊是編碼方式,還有QString
和char *
類型的不同。
API
說明:無特殊API
用到的上面已經介紹過。
代碼實現:
void MainWindow::on_actionSAVE_triggered()
{
// 如果剛打開編輯器開始寫東西,此時path爲空就需要通過getSaveFileName獲取一個路徑
if(path.isEmpty())
{
path = QFileDialog::getSaveFileName();
}
const char *fileName = codec->fromUnicode(path).data();
// 打開文件並讀取內容,並放進編輯區
FILE *fp = fopen(fileName, "wb");
if(fp == NULL)
{
cout << "on_actionSAVE_triggered open file err";
}
// 獲取編輯區的內容,返回QString
QString str = ui->textEdit->toPlainText();
// 將QString轉換爲char * 類型
const char *buf = str.toStdString().data();
fputs(buf, fp);
// 關閉文件
fclose(fp);
}
編譯運行
思路:首先判斷一下需要運行的文件是否已經存在,如保存文件中出現的第二種情況,一打開編輯器就開始編輯的文件,還沒保存到本地,那麼就需要先保存到本地。然後通過gcc filename.c -o filename
生成可執行文件,再執行可執行程序即可。第一步獲取filename
:通過QString的replace
函數將路徑最後的.c
去掉即可。第二步執行可執行程序。
注意:執行以上的兩部都需要在終端執行,直接調用system函數即可。如果編譯出錯,那麼就不能繼續執行,需終端停留在報錯頁面,使用cmd /k
可實現終端停留
API
說明:
replace()
QString
中的函數,替換字符串中指定字符串。QString("gcc %1 -o %2").arg(arg1).arg(arg2)
QString
格式化ui->textEdit->toPlainText()
獲取文本編輯框內容
代碼實現:
void MainWindow::on_actioncomplie_triggered()
{
if(path.isEmpty())
{
// 如果沒有路徑則需要保存一下才能運行
this->on_actionSAVE_triggered();
}
QString demo = path;
// 生成的目標文件名
demo.replace(".c", "");
// gcc filename.c -o filename
QString cmd = QString("gcc %1 -o %2").arg(path).arg(demo);
// system執行成返回0
int ret = system(codec->fromUnicode(cmd).data());
if(ret != 0)
{
// cmd /k 停留在終端
cmd = QString("cmd /k gcc %1 -o %2").arg(path).arg(demo);
system(codec->fromUnicode(cmd).data());
return;
}
QString target = QString("cmd /k %1").arg(demo);
system(codec->fromUnicode(target).data());
system("cmd");
}
改變字符編碼
思路:通過codec->fromUnicode(path)
或codec->toUnicode(buf)
兩個API
實現編碼轉換功能。由於字符編碼需要在好幾個槽函數中使用,所以思考定義一個全局變量,通過這個全局變量的狀態來判斷如何轉換。通過ui->label->setText
在左下角實時顯示當前的編碼方式。
注意:別的槽函數使用,所以需要使用全局變量。
API
說明:
replace()
QString
中的函數,替換字符串中指定字符串。QString("gcc %1 -o %2").arg(arg1).arg(arg2)
QString
格式化ui->label->setText("當前以GBK顯示,切換編碼後請重新打開文件")
將制定內容顯示在label
中。
代碼實現:
// UTF_8轉換函數
void MainWindow::on_actionUTF_8_triggered()
{
// 按下轉換按鍵,爲UTF_8
flag = utf_8;
ui->label->setText("當前以UTF-8顯示,切換編碼後請重新打開文件");
}
// GBK轉換函數
void MainWindow::on_actionGBK_triggered()
{
// 按下按鍵轉換爲GBK
flag = GBK;
ui->label->setText("當前以GBK顯示,切換編碼後請重新打開文件");
}
退出、複製、粘貼、剪切、撤銷
思路:直接調用QT自帶的相應的功能函數。
API
說明:
ui->textEdit->copy()
複製ui->textEdit->paste()
粘貼ui->textEdit->cut()
剪切ui->textEdit->undo()
撤銷
代碼實現:
// 複製
void MainWindow::on_actioncopy_triggered()
{
ui->textEdit->copy();
}
// 粘貼
void MainWindow::on_actionpaste_triggered()
{
ui->textEdit->paste();
}
// 剪切
void MainWindow::on_actioncut_triggered()
{
ui->textEdit->cut();
}
// 撤銷
void MainWindow::on_actionundo_triggered()
{
ui->textEdit->undo();
}
// 退出系統
void MainWindow::on_actionQUITE_triggered()
{
exit(0);
}
完整代碼
完整的工程代碼連接:https://github.com/wtzhu13/CPPOrCProectDemo/tree/master/IDE
**彩蛋:**這個項目中還包含其他一些練手小項目,後續會慢慢更新,不斷往裏添加。