好久没有写博客了,鸽了好久(咕咕咕),已经基本完成了毕业设计的全部的基本功能。下面说一下目前为止实现的功能,设计思路,方案,和一部分错误。
一.题目要求以及完成情况题目名称:lua语言简易集成开发环境
课题要求:完成以下功能: 1、支持工程; 2、代码编辑; 3、即时调试。
课题简介: 开发一个简易lua集成开发环境,完成基本的代码编辑、运行、运行结果展示及代码调试。
目前完成情况:
目前已经实现了本地文件的读取,修改,即时保存以及另存为功能;实现了代码编辑,代码高亮显示,行号显示,以及实现部分快捷键(譬如ctrl+c,ctrl+v);实现了代码运行,打开指定工作区的终端,实现断点运行,断点调试,显示中间变量以及此时运行的行号;集成了一个Lua的相关帮助文档,内容是根据我的Lua语言学习经验和菜鸟教程结合而成,做了个小型界面,点击按钮实现页面跳转。
工具:qt creator(c++,qml和javascript)
二.功能介绍(思路,方法,代码,及部分错误) (1)本地文件的读取,修改,即时保存以及另存为功能可以说,这项功能是实现课题的基础之基础,也是重中之重。在写的时候,因为明确使用的语言是c++和qm,所以当时想过主要两种思路,一方面是可以用c++的文件 *** 作功能,另一方面可以使用qml的文件 *** 作。因为本着学习新知识的目的,所以学习并使用了qml对文件的相关 *** 作。
qml进行本地文件 *** 作主要使用的是QFile类,QFile类提供了一个用于读取和写入文件的接口,通过QFile类来实现相应的功能。同时在网上我看到有些人还会使用QTextStream类, QTextStream类为读写文本提供了一个方便的接口。但是我没有用。我直接使用了QFile中的open(),write(),read()等函数对文件的读写。同时这个转码,转类型问题,一定要谨记此时各个量的类型,在本次课题中出现了大量的QString和String的使用和转换,本地资源url类型与string的相关 *** 作,还有toUtf8等类型变幻的问题。
代码如下:
File.h
#ifndef QT_HUB_FILE_H
#define QT_HUB_FILE_H
#include
class File : public QObject
{
Q_OBJECT
public:
File();
Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
QString source() const;
void setSource(const QString &source);
QString text() const;
void setText(const QString &text);
signals:
void sourceChanged();
void textChanged();
private slots:
void readFile();
private:
QString m_source;
QString m_text;
};
#endif // FILE_H
File.cpp
#include "File.h"
#include
#include
File::File()
{
connect(this, SIGNAL(sourceChanged()), this, SLOT(readFile()));
}
void File::setSource(const QString &source)
{
m_source = source;
emit sourceChanged();
}
QString File::source() const
{
return m_source;
}
void File::setText(const QString &text)
{
QFile file(m_source);
m_text="";
if (!file.open(QIODevice::WriteOnly)) {
m_text = "";
qDebug() << "Error:" << m_source << "open failed!";
}
else {
qint64 byte = file.write(text.toUtf8());
if (byte != text.toUtf8().size()) {
m_text = text.toUtf8().left(byte);
qDebug() << "Error:" << m_source << "open failed!";
}
else {
m_text = text;
}
file.close();
}
emit textChanged();
}
void File::readFile()
{
QFile file(m_source);
if (!file.open(QIODevice::ReadOnly)) {
m_text = "";
qDebug() << "Error:" << m_source << "open failed!";
}
m_text = file.readAll();
emit textChanged();
}
QString File::text() const
{
return m_text;
}
main.cpp (别忘了注册类型)
#include "File.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType("wenzi", 1, 0, "File");
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
部分经验和错误:
(1)在实现选择本地文档读取,修改,保存,另存为关键的功能,不仅仅只有对本地文件进行读写这个功能很重要,获取指定文件的路径也十分重要。在课题中我使用了FileDialog控件,实现了打开文件选择器,在点击文件后(omAccepted),能够获得一个文件的路径,类型为url,差点给我整不会了(第一次见这种类型的变量),后来写了一个简单的JavaScript将他转化为了string赋值给了指定变量(指定file.source)代码如下:
mian.qml
MenuBar{//功能栏
id:gongnenglan
Menu{
id:wenjian
title: "文件"
property string midurl: ""
MenuItem{
text: "打开文件"
onTriggered: fileDialog1.open()
}
MenuItem{
text: "另存为"
onTriggered: fileDialog2.open()
}
MenuItem{
text: "退出"
onTriggered: Qt.quit()
}
function changeurl(FileDialog){
wenjian.midurl=(fileDialog1.file).toString();
var mid=(wenjian.midurl).toString();
var midurlchange=mid.substring(8);
file.source=midurlchange;
}
function savebyurl(FileDialog){
wenjian.midurl=(fileDialog2.file).toString();
var mid2=(wenjian.midurl).toString();
var savebyurl1=mid2.substring(8);
savefile.source=savebyurl1;
}
FileDialog {
id: fileDialog1
folder: StandardPaths.standardLocations(StandardPaths.DesktopLocation)[0] //默认打开桌面文件夹
fileMode: FileDialog.OpenFile
onAccepted: {
wenjian.changeurl(fileDialog1)
t1.text=file.text
}
}
FileDialog {
id: fileDialog2
folder: StandardPaths.standardLocations(StandardPaths.DesktopLocation)[0] //默认打开桌面文件夹
fileMode: FileDialog.OpenFile
options: FileDialog.SaveFile
onAccepted: {
wenjian.savebyurl(fileDialog2)
savefile.text=t1.text
}
}
}
File {
id: file
source: "F:/Luap/learn/choosepath.lua"
onSourceChanged: {
t1.text=file.text
}
}
File{
id:savefile
source: ""
}
与上述问题非常类似的问题还有,下面还会登场。
(2)代码编辑,代码高亮显示,行号显示,以及实现部分快捷键(譬如ctrl+c,ctrl+v)如果实现了本地文件读取,那么代码编辑功能的基础工作就算完成了。接下来就是选择使用什么控件来显示代码,可以用TextArea,TextEidt两种控件,带是需要实现代码编辑,那么最好使用TextEdit。选择了TextEdit作为代码显示和编辑的控件后,我们要考虑在文本变化后需要保存,加载后代码会是什么状态,同时还要考虑如果文件代码行数太多,如何显示超出显示屏范围的代码。行号显示则是非常好实现。
最后则是代码高亮,为什么单独分出一段说,是因为这东西足足花了两周的时间才完成(明明是很简单东西)。在网上我找到了三种实现方法:使用文本块拼接,使用富文本标签,以及QSyntaxHighlighter类实现。网上有人说可以用文本块拼接,找了半天资料都不知道咋拼接。第二种方法使用富文本标签,确实也能实现功能,但是由于我此时实现了本地读取和即时保存,它会直接污染本地文件,出现类似于html的头部内容,内容全部消失。第三种方法是使用QSyntaxHighlighter类,QSyntaxHighlighter类允许定义语法突出显示规则,此外,还可以使用该类查询文档的当前格式或用户数据。在使用时到最后一定要导入文本格式,使用setDocument,就这个问题纠结了好久。
代码如下:
HighLighter.h
#ifndef CODEHIGHLIGHTER_H
#define CODEHIGHLIGHTER_H
#include
#include
#include
class HighLighter: public QSyntaxHighlighter
{
Q_OBJECT
public:
HighLighter(QTextDocument *parent = 0);
Q_INVOKABLE void setDocument(QQuickTextDocument *pDoc);
protected:
Q_INVOKABLE void highlightBlock(const QString &text) override;
private:
struct HighlightingRule
{
QRegExp pattern;
QTextCharFormat format;
};
QVector highlightingRules;
QRegExp commentStartExpression; //多行注释开始标识符
QRegExp commentEndExpression; //多行注释结束标识符
QTextCharFormat keywordFormat; //关键字
QTextCharFormat classFormat; //类
QTextCharFormat singleLineKey; //单行关键字
QTextCharFormat singleLineValue; //单行值
QTextCharFormat singleLineCommentFormat;//单行注释
QTextCharFormat multiLineCommentFormat; //多行注释
QTextCharFormat quotationFormat; //字符串标识符
QTextCharFormat functionFormat; //方法标识符
};
#endif // CODEHIGHLIGHTER_H
HighLighter.cpp
#include "HighLighter.h"
#include
#include
HighLighter::HighLighter(QTextDocument *parent)
: QSyntaxHighlighter(parent)
{
HighlightingRule rule;
//对于下面正则表达式,标记为紫色,类名称
classFormat.setFontWeight(QFont::Bold);
classFormat.setForeground(Qt::darkMagenta);
rule.pattern = QRegExp("\\b[A-Za-z]+:\\b");
rule.format = classFormat;
highlightingRules.append(rule);
rule.pattern = QRegExp("\\b[A-Za-z]+\\.\\b");
rule.format = classFormat;
highlightingRules.append(rule);
//字符串,标记深红色
quotationFormat.setForeground(Qt::darkRed);
rule.pattern = QRegExp("\".*\"");
rule.format = quotationFormat;
highlightingRules.append(rule);
rule.pattern = QRegExp("'.*'");
rule.format = quotationFormat;
highlightingRules.append(rule);
//函数标记为斜体蓝色
functionFormat.setFontItalic(true);
functionFormat.setForeground(Qt::blue);
rule.pattern = QRegExp("\\b[A-Za-z0-9_]+(?=\\()");
rule.format = functionFormat;
highlightingRules.append(rule);
//关键字
QStringList keywords = {
"and", "break", "do", "else", "elseif", "end", "false",
"for", "function", "if", "in", "local", "nil", "not", "or",
"repeat", "return", "then", "true", "unitl", "while", "goto"
};
//对于下面关键字部分,标记为深蓝色
keywordFormat.setForeground(Qt::darkBlue);
keywordFormat.setFontWeight(QFont::Bold);
QStringList keywordPatterns;
for(int i=0; i= 0) {
int length = expression.matchedLength();
setFormat(index, length, rule.format);
index = expression.indexIn(text, index + length);
}
}
setCurrentBlockState(0);
int startIndex = 0;
if (previousBlockState() != 1)
startIndex = commentStartExpression.indexIn(text);
while (startIndex >= 0) {
int endIndex = commentEndExpression.indexIn(text, startIndex);
int commentLength=0;
if (endIndex == -1) {
setCurrentBlockState(1);
commentLength = text.length() - startIndex;
} else {
commentLength = endIndex - startIndex
+ commentEndExpression.matchedLength();
}
setFormat(startIndex, commentLength, multiLineCommentFormat);
startIndex = commentStartExpression.indexIn(text, startIndex + commentLength);
}
}
void HighLighter::setDocument(QQuickTextDocument *pDoc)
{
QSyntaxHighlighter::setDocument(pDoc->textDocument());
}
main.qml
Flickable{
id:flicka
x: -352
y: -738
height: 660
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.leftMargin: 0
anchors.topMargin: 0
anchors.fill: parent
contentWidth: t1.paintedWidth
contentHeight: t1.paintedHeight
clip: true
function ensureVisible(r)
{
if (contentX >= r.x)
contentX = r.x;
else if (contentX+width <= r.x+r.width)
contentX = r.x+r.width-width;
if (contentY >= r.y)
contentY = r.y;
else if (contentY+height <= r.y+r.height)
contentY = r.y+r.height-height;
}
File {
id: file
source: "F:/Luap/learn/choosepath.lua"
onSourceChanged: {
t1.text=file.text
}
}
Column{
id:showlinecount
property string duandian:"";
property int duandiannum: 0;
property string midduandian: "";
//property int midindex: 0;
x: 15
y: 15
width: 24
height: 943
Repeater{
model: t1.lineCount
Rectangle{
width: parent.width
height: 34
color: "red"
Rectangle{
id:kuang
anchors.fill: parent
width: parent.width
height: parent.height
radius: 0
color: "#E5E4E2"
//visible: fasle
}
Text{
id:showlinenum
anchors{
horizontalCenter: parent.horizontalCenter
}
text: index+1
color: "black"
}
MouseArea{
anchors.fill: parent
width: parent.width
height: parent.height
onClicked: {
jiajianduandian();
}
function jiajianduandian(){
if(kuang.visible==false)
{
kuang.visible=true
var midduandian2=showlinecount.duandian.split(" ");
showlinecount.duandiannum=showlinecount.duandiannum-1;
showlinecount.duandian="";
//var mindindex=index
for(let i=0;i
部分经验和错误:
(1)给TextEdit加滚动条显示超出显示屏范围的文字有两种方式,一种是在TextEdit外面套Flickable,使整个区域可以移动拖拽,另一种是在TextEdit外面套ScrollView,使其中的内容实现滚动,我这里使用的是第一种方式,在后面Lua文档处使用了第二种方式。
(2)要及时更新t1和file的text内容,详情请看第二、三篇,因为在文件源更换时没有及时更新t1.text导致会出现切换文件时需要点击两次才能更换的情况
(3)实现了代码运行,打开指定工作区的终端,实现断点运行,断点调试,显示中间变量以及此时运行的行号要想实现Lua代码运行,首先肯定要安装Lua的环境。设置完Lua语言的环境变量后,测试能否运行Lua文件,Lua环境情况。打开cmd,输入lua会进入lua的交互式界面。
在本次课题中我主要使用了c++的system()直接运行,将获取到的file.source和lua字符串拼接到一起,然后将拼接器的字符串传入system()中运行,系统控制台输出结果。
打开终端,这个功能有四种实现方式(我知道的),第一种直接system(“cmd.exe”);第二种利用ShellExecuteA函数,通过该函数能够打开外部程序;第三种是获取当前窗口句柄,然后可以修改控制台位置,颜色,背景等;第四种可以利用QProcess类打开外部程序。此处我使用了第二种, 代码如下:
ShellExecuteA(NULL, "open", "cmd.exe", NULL,"F:/Luap/learn/", SW_SHOW);
断点运行和断点调试,事实上我们可以使用Lua自带的debug库来帮助我们完成功能,但是首先我们要先完成行号显示这一功能,在行号的每个所在区域添加MouseArea,时期被点击后有相应的信息让我们知道断点已被设置,设置在何处。以我目前的知识来看,想要实现断点等相关功能有三种方法,三种思路。第一种是cpp文件中导入Lua,使cpp内容能够实现对Lua相应函数,然后在cpp文件中使用c++结合相应的Lua函数实现断点;第二种是使用外部的Lua文件,在相应的工作夹中调用相应的Lua文件,利用Lua中的trace实现调用其他Lua文件中已经写好的函数,最后一种是直接在源文件中修改,在第一行加入响应函数,在后面调用。我也了解到其他调试器断点是如何实现的,有的是利用int3指令实现int3断点,还有一系列内存断点,条件断点。在这里我选择的是第三种方法。
断点功能是如何实现的呢。如果是简单的断电运行可以通过Lua的debug库中的debug.debug()实现,它会使用户进入一个交互界面,程序运行到这里是会暂停,可以输入一些简单的调试命令,输入cont来进行下一部分程序。但是断点调试又是另一回事了,在断点调试中,我们不仅需要显示此时中间局部变量的情况,还需要显示此时在第几行,同时还需要每一行执行都需要汇报。这里我们需要首先定义自己的hook函数,以备后面调用时使用。我写的hook函数如下:
function hook(event,line)
i=1 --全局变量,建议大写,初始化i
print('table of local variable:')
repeat local k,v = debug.getlocal(2,i)
print(k,v) --打印局部变量
i = i + 1
until not k
i=1 --初始化i
print('running location:')
print('event line')
print(event,line) --打印行数
debug.debug() --断点交互
end
在后面时就可以直接调用,使用debug.sethook()函数设置hook函数,其中debug.sethook()的三种调用方式中,我们选择"l",这样会使我们写的hook在sethook后的每一行(包括自己)都会被调用。
代码如下:
Run.h
#ifndef RUN_H
#define RUN_H
#include
#include
#include
class Run : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QString source)
Q_PROPERTY(QString duandian)
Q_PROPERTY(int duandian_num)
Q_INVOKABLE void runLua(const QString &source);
Q_INVOKABLE QString chuliquanwen(const QString &text);
Q_INVOKABLE QString duandianyunxing(const QString &text,const QString &duandianji,const qint32 &duandiannum);
Q_INVOKABLE QString shanduandian(const QString &duandian,const qint32 midindex);
Q_INVOKABLE QString duandiantiaoshi(const QString &text,const QString &duandianji);
//Q_INVOKABLE QString showlocal(const QString &text,const QString &duandianji,const qint32 &duandiannum);
//QStringList duandian;
//qint32 duandian_num;
Q_PROPERTY(QString midtext1)
//Q_PROPERTY(int duandian_num1)
QString s[100];
QString t[100];
private:
QString midtext1;
QString midduandian1;
};
#endif // RUN_H
Run.cpp
//#include
#include
#include"Run.h"
#include
#include
#include
#include
using namespace std;
void Run::runLua(const QString &source){
string a=source.toUtf8().toStdString();
string b="lua ";
//string d=" >F:/Luap/learn/1.txt";
b.append(a);
//b.append(d);
char c[100]={""};
strcpy(c,b.data());
system(c);
//QString::fromLocal8Bit(p.readAllStandardOutput())
}
QString Run::chuliquanwen(const QString &text){
midtext1="";
for(int i=0;i<100;i++){
s[i]="";
}
for(int i=0;i<100;i++){
s[i]=text.section("\n",i,i);
if(s[i]=="")
continue;
}
for(int i=0;i<100;i++){
if(s[i]=="\n"||s[i]=="\t"||s[i]=="")
continue;
else if(s[i].contains("function")||s[i].contains("end")||s[i].contains("--")||s[i].contains("if")||s[i].contains("else")||s[i].contains("return"))
s[i]=s[i]+"\n";
else
s[i]="debug.debug()"+s[i]+"\n";
}
for(int i=0;i<100;i++){
if(s[i]=="")
continue;
else
midtext1=midtext1+(QString)s[i];
}
return midtext1;
}
QString Run::shanduandian(const QString &duandian,const qint32 midindex){
// for(int i=0;i<100;i++){
// t[i]="";
// }
for(int i=0;i<100;i++){
t[i]=duandian.section(" ",i,i);
if(t[i]=="")
continue;
}
midduandian1="";
for(int i=0;i<100;i++){
if(t[i]==midindex){
}
else{
midduandian1=midduandian1+" "+t[i];
}
}
return midduandian1;
}
QString Run::duandianyunxing(const QString &text,const QString &duandianji,const qint32 &duandiannum){
midtext1="";
for(int i=0;i<100;i++){
s[i]="";
}
for(int i=0;i<100;i++){
t[i]="";
}
for(int i=0;i<100;i++){
s[i]=text.section("\n",i,i);
// if(i==0)
// s[i]="function hook(event,line) i=1 repeat local k,v = debug.getlocal(2,i) print(k,v) i = i + 1 until not k print(event,line) debug.debug() end"+s[i];
if(s[i]=="")
continue;
}
for(int i=0;i<100;i++){
t[i]=duandianji.section(" ",i,i);
if(t[i]==""){
//aa=i-1;
break;
}
}
for(int i=0;i<100;i++){
for(int j=(duandiannum-1);j>=0;j--){
if(i==t[j].toInt()){
if(s[i]=="\n"||s[i]=="\t"||s[i]==""){
continue;
}
else if(s[i].contains("function")||s[i].contains("end")||s[i].contains("--")||s[i].contains("if")||s[i].contains("else")||s[i].contains("return")){
s[i]=s[i]+"\n";
}
else if(s[i].contains("debug.debug()")){
s[i]=s[i];
}
else{
s[i]=(QString)"i=1 repeat local k,v = debug.getlocal(1,i) print(k,v) i = i + 1 until not k debug.debug() i=1"+(QString)" "+s[i]+"\n";
i=0;
t[j]="";
}
}
else if(i!=t[j].toInt()){
if(s[i].contains("\n")){
s[i]=s[i];
}
else
s[i]=s[i]+"\n";
//break;
}
}
}
for(int i=0;i<100;i++){
if(s[i]==""){
continue;
}
else if(s[i].contains("\n")){
s[i]=s[i];
}
else{
s[i]=s[i]+"\n";
}
}
for(int i=0;i<100;i++){
if(s[i]==""||s[i].contains("--"))
continue;
else
midtext1=midtext1+(QString)s[i];
}
return midtext1;
}
QString Run::duandiantiaoshi(const QString &text,const QString &duandianji){
midtext1="";
QString a;
for(int i=0;i<100;i++){
s[i]="";
}
for(int i=0;i<100;i++){
s[i]=text.section("\n",i,i);
if(i==0){
a=s[i];
s[i]="function hook(event,line) i=1 print('table of local variable:') repeat local k,v = debug.getlocal(2,i) print(k,v) i = i + 1 until not k i=1 print('running location:') print('event line') print(event,line) debug.debug() end "+a+"\n";
}
// if(s[i]=="")
// continue;
}
for(int i=0;i<100;i++){
t[i]="";
}
t[0]=duandianji.section(" ",0,0);
for(int i=0;i<100;i++){
if(i==t[0].toInt()){
if(s[i]=="\n"||s[i]=="\t"||s[i]==""){
continue;
}
else if(s[i].contains("function")||s[i].contains("end")||s[i].contains("--")||s[i].contains("if")||s[i].contains("else")||s[i].contains("return")){
s[i]=s[i]+"\n";
}
else if(i==0){
s[0]="function hook(event,line) i=1 print('table of local variable:') repeat local k,v = debug.getlocal(2,i) print(k,v) i = i + 1 until not k i=1 print('running location:') print('event line') print(event,line) debug.debug() end debug.sethook(hook,'l') "+a;
}
else{
s[i]=(QString)"debug.sethook(hook,'l')"+(QString)" "+s[i]+"\n";
}
}
else if(i!=t[0].toInt()){
if(s[i].contains("\n")){
s[i]=s[i];
}
else
s[i]=s[i]+"\n";
//break;
}
}
for(int i=0;i<100;i++){
if(s[i]==""){
continue;
}
else if(s[i].contains("\n")){
s[i]=s[i];
}
else{
s[i]=s[i]+"\n";
}
}
for(int i=0;i<100;i++){
if(s[i]==""||s[i].contains("--"))
continue;
else
midtext1=midtext1+(QString)s[i];
}
return midtext1;
}
Terminal.h
#ifndef TERMINAL_H
#define TERMINAL_H
#include
#include
#include
#include
class Terminal:public QObject
{
Q_OBJECT
public:
Q_INVOKABLE void zhongduan();
private:
QProcess myProcess;
};
#endif // TERMINAL_H
Terminal.cpp
#include"Terminal.h"
#include
#include
#include
#include
#include
using namespace std;
void Terminal::zhongduan(){
ShellExecuteA(NULL, "open", "cmd.exe", NULL,"F:/Luap/learn/", SW_SHOW);
}
部分经验和错误:
(1)JavaScript中我QString类型的数据无法处理,直接停了,JavaScript引擎等待下一步指令,我JavaScript不是特别熟,不是特别明白,所以我在JavaScript的function外将QString类型数据先转换成String类型再处理。
(2)由于Qt版本过高(应该是这个原因),我在使用QProcess打开cmd.exe无法d出d窗窗口,但是任务管理器显示它在,而且还在运行。
(4)集成了一个Lua的相关帮助文档,内容是根据我的Lua语言学习经验和菜鸟教程结合而成,做了个小型界面,点击按钮实现页面跳转为了增加我的工作量,使课设更完善一点,于是我给它加了个界面,同时还集成了一个Lua帮助文档,里面内容是我的Lua学习总结和Lua菜鸟教程。
界面的话,我有两个思路,第一个是写在不同的qml文件中,在main.cpp加载时先加载界面的qml文件,在点击按钮后跳转到另一界面,第二个是直接写在一个qml文件中,利用窗口Window的visible属性实现页面的切换。我选择的是第一种方法,在点击按钮后还会动态加载main.qml,同时隐藏界面的窗口。
截图如图1:
图1 界面
点击打开文件按钮后会跳转到代码区,如图2:
图2 代码区
是不是感觉右边空荡荡的,那确实是,所以我就想加一个Lua的帮助文档,此时点击其他按钮会d出一个Lua文档,如下图:
点击退出后能够关掉帮助文档,之前是因为点这个小窗口的关闭按钮会父窗口和子窗口都观点,结果加了退出按钮后点关闭按钮就只关子窗口了。
点击上面的文本会跳转到相应的位置,这一点可以通过点击后改变光标位置(cursorPosition)来实现。同时这里TextArea使用的是ScrollView来实现文本的滚动,上下翻阅。
代码如下:
login.qml 界面的实现
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Controls 2.14
import Qt.labs.folderlistmodel 2.2
import QtQuick.Shapes 1.12
import Qt.labs.platform 1.1
import QtQuick.Window 2.14
import wenzi 1.0
Window{
id:login
width: 1920
height: 1030
visible: true
color: "gray"
property int filenum: 1
Image {
id: loginbac
fillMode: Image.PreserveAspectFit
width: 1920
height: 1030
visible: true
source: "file:\F:\qtp\test2\loginbcak.png"
}
File{
id:file1
source: ""
}
Button{
id:choose
x: 1502
y: 882
text: "打开文件"
onClicked: {
login.showmain();
//close("qrc:/login.qml")
}
}
function showmain(){
panelLoader.setSource("qrc:/main.qml");
login.visible=false;
}
Loader{
id:panelLoader
function setSource(source){
panelLoader.source=source
}
}
Text {
id: biaoti1
x: 605
y: 136
width: 711
height: 80
text: qsTr("Lua简易集成开发环境")
font.pixelSize: 80
font.bold: true
}
Rectangle {
id: rectangle
x: 309
y: 260
width: 430
height: 662
color: "#ffffff"
Text {
id: gongneng
x: 0
y: 8
width: 430
height: 60
text: qsTr("目前已实现主要功能:")
font.pixelSize: 40
}
Text {
id: gongnenglieju
x: 4
y: 108
width: 422
height: 335
font.pixelSize: 40
text:qsTr("1.本地文件的读取,修\n改,存储\n2.代码运行功能\n3.代码高亮显示功能\n4.断点运行和单步调试\n功能")
}
Image {
id: lua_pic1
x: 115
y: 435
width: 200
height: 200
visible: true
source:"file:\F:\qtp\test2\luapic.png"
}
}
}
main.cpp 不要忘记修改首先打开的qml文件
const QUrl url(QStringLiteral("qrc:/login.qml"));
main.qml
Window{
id:luawendang
x: 1546
y: 110
width: 369
height: 920
visible: true//fasle
color: "#ffffff"
Rectangle{
id:sousuokuang
x: 0
y: 0
width: parent.width
height: 40
color: "gray"
Button{
id:selectbt2
x:0
y:0
width: parent.width
height: parent.height
text:"退出"
onClicked: {
luawendang.visible=false
}
}
}
File{
id:luawendang_file
source:"f:/Luap/learn/luahelp.txt"
}
Rectangle{
id:mulu
x:0
y:40
width:369
height: 180
Text{
id:jiaocoheng
anchors.top: parent
x: 0
y:0
height: 20
width: 180
text: qsTr("Lua教程")
MouseArea{
anchors.fill: parent
onClicked: {
luawendang_text.cursorPosition=0; //光标位置根据自己的情况调整
}
}
}
Text {
id: anzhuang
width: 180
x:180
y:0
text: qsTr("Lua基本语法")
MouseArea{
anchors.fill: parent
onClicked: {
luawendang_text.cursorPosition=2395;
}
}
}
Text{
id:jibenyufa
anchors.top: parent
x: 0
y:20
height: 20
width: 180
text: qsTr("Lua数据类型")
MouseArea{
anchors.fill: parent
onClicked: {
luawendang_text.cursorPosition=4150;
}
}
}
Text{
id:shujuleixing
anchors.top: parent
x:180
y:20
height: 20
width: 180
text: qsTr("Lua变量")
MouseArea{
anchors.fill: parent
onClicked: {
luawendang_text.cursorPosition=8650;
}
}
}
Text{
id:luabianliang
anchors.top: parent
x:0
y:40
height: 20
width: 180
text: qsTr("Lua循环")
MouseArea{
anchors.fill: parent
onClicked: {
luawendang_text.cursorPosition=12000;
}
}
}
}
ScrollView{
id:luawendang_scro
x: 0
y:220
width: 369
height: 690
TextArea{
id:luawendang_text
cursorVisible: true
height: 690
x: 0
y:180-mulu.height
width: 369
textFormat:TextEdit.AutoText
text: luawendang_file.text
wrapMode: Text.WordWrap
selectByMouse: true
}
}
}
}
部分经验和错误:
要注意ScrollView的使用,如果没必要最好有确定的位置和宽高,最早一版直接按照上面矩形框显示的x,y,高宽设置的,结果跑半天飞了,下面出现空白,最后上滚下滚一个来回后文字位置就对不上了,且无法点击文本,点了直接拉到最后。
qml照片使用的资源路径,三种路径三种方法要牢记。
以上就是目前的工作进度,准备写论文了,大概十几天后就会答辩,大学四年挺快的,说实话。希望我们都能有光明的未来。
PS:大概最后还会发一期来完善一下。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)