From 3046d9c7362b1a2a69959ffd03273986e7be1c52 Mon Sep 17 00:00:00 2001 From: CCA8798 <2044187229@qq.com> Date: Wed, 24 Sep 2025 18:05:56 +0800 Subject: [PATCH 1/2] 25y27w01p --- .gitattributes | 2 + .gitignore | 32 ++++++++ CMakeLists.txt | 38 +++++++++ Console.cpp | 5 ++ Console.h | 178 +++++++++++++++++++++++++++++++++++++++++++ ConsoleInQt_global.h | 12 +++ 6 files changed, 267 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 Console.cpp create mode 100644 Console.h create mode 100644 ConsoleInQt_global.h diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..259148f --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e15f929 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.5) + +message(${PROJECT_SOURCE_DIR}/../MINGW64_MINSIZERELEASE) + +project(ConsoleInQt LANGUAGES CXX) + +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../MINGW64_MINSIZERELEASE) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../MINGW64_MINSIZERELEASE) +set(CMAKE_BINARY_DIR ${PROJECT_SOURCE_DIR}/../MINGW64_MINSIZERELEASE) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../MINGW64_MINSIZERELEASE) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_PREFIX_PATH "F:/Software/Qt5/Qt5.14.2/5.14.2/mingw73_64") + + +find_package(Qt5 COMPONENTS Widgets REQUIRED) + +add_library(ConsoleInQt SHARED + ConsoleInQt_global.h + Console.cpp + Console.h +) + +target_link_libraries(ConsoleInQt PRIVATE Qt5::Widgets) + +target_compile_definitions(ConsoleInQt PRIVATE CONSOLEINQT_LIBRARY) +set(MY_CUSTOM_COMMAND "${CMAKE_BINARY_DIR}/copy.bat") +message("Executing COPYING: ${MY_CUSTOM_COMMAND}") +## 添加自定义命令,在编译完成后执行 +add_custom_command( + TARGET ConsoleInQt POST_BUILD + COMMAND ${MY_CUSTOM_COMMAND} + COMMENT "Copying include files after build") diff --git a/Console.cpp b/Console.cpp new file mode 100644 index 0000000..3ad6197 --- /dev/null +++ b/Console.cpp @@ -0,0 +1,5 @@ +#include "Console.h" +using namespace ConsoleInQt; +Console::Console(QWidget* parent) : QWidget(parent) +{ +} diff --git a/Console.h b/Console.h new file mode 100644 index 0000000..3e4760a --- /dev/null +++ b/Console.h @@ -0,0 +1,178 @@ +#ifndef CONSOLE_H +#define CONSOLE_H + +#include "ConsoleInQt_global.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 添加定时器用于焦点延迟设置 + +#define _CIQ_HEIGHT_MAX_ 16777215 + +namespace ConsoleInQt { + + //控制台模式枚举 + enum class ConsoleModeEnum { + Shell=1, //Shell模式 + Text=2 //普通文本模式 + }; + +class CONSOLEINQT_EXPORT Config : public QObject{ + Q_OBJECT +public: + explicit Config(QObject* parent=nullptr){ + Q_UNUSED(parent); + }; + ~Config(){}; + +protected: + + //=========^全局设置^=========// + size_t ConsoleMode=static_cast(ConsoleModeEnum::Shell); //控制台模式 + QString WelcomeMessage=""; //欢迎消息 + QString BackgroundColor="black"; //背景颜色 + QString TextCursorColor="white"; //光标颜色 + QString TextColor="white"; //文本颜色 + QString TextSize="20"; //字体大小 + +public slots: + + //=========^全局设置方法^=========// + inline void setWelcomeMessage(const QString& WelcomeMessageSc){WelcomeMessage=WelcomeMessageSc;} + inline QString getWelcomeMessage(void) const{return WelcomeMessage;}; + + inline void setBackgroundColor(const QString& BackgroundColorSc){BackgroundColor=BackgroundColorSc;} + inline QString getBackgroundColor(void) const{return BackgroundColor;}; + + inline void setTextColor(const QString& TextColorSc){TextColor=TextColorSc;} + inline QString getTextColor(void) const{return TextColor;} + + inline void setTextSize(const QString& TextSizeSc){TextSize=TextSizeSc;} + inline QString getTextSize(void) const{return TextSize;} + + inline size_t TestingOutput() const{ + return ConsoleMode; + } //测试输出 + + inline QString getCurrentConfig(void) const { + return QString("background: %1; color: %2; caret-color: %3; font-size: %4px; border-width: 0; border-style: outset;") + .arg(BackgroundColor, TextColor, TextCursorColor, TextSize); + } //获取当前全局设置 +}; + +class CONSOLEINQT_EXPORT Console : public QWidget +{ + Q_OBJECT + +//私有方法 +private: + QVBoxLayout* CIQ_mainLayout=new QVBoxLayout(this); //主布局 + QScrollArea CIQ_scrollArea=QScrollArea(this); //滚动区域,隶属this + QWidget CIQ_consoleWidget=QWidget(&CIQ_scrollArea); //控制台窗口,隶属CIQ_scrollArea + QVBoxLayout* CIQ_consoleLayout=new QVBoxLayout(&CIQ_consoleWidget); //控制台窗口布局,隶属CIQ_consoleWidget + + // 用于焦点管理的私有方法 + void setFocusToCurrentInput() { + if (CIQ_consoleLayout->count() > 0) { + QWidget* lastWidget = CIQ_consoleLayout->itemAt(CIQ_consoleLayout->count()-1)->widget(); + if (lastWidget) { + // 使用定时器确保在事件循环结束后设置焦点 + QTimer::singleShot(50, [lastWidget]() { + lastWidget->setFocus(); + if (QLineEdit* input = qobject_cast(lastWidget)) { + input->setCursorPosition(input->text().length()); + } + }); + } + } + } + + //初始化主布局和控制台窗口布局 + void initLayouts(void) { + CIQ_mainLayout->setMargin(0); + CIQ_mainLayout->setSpacing(0); + CIQ_mainLayout->setContentsMargins(0,0,0,0); + CIQ_mainLayout->setAlignment(Qt::AlignTop); + CIQ_consoleLayout->setMargin(0); + CIQ_consoleLayout->setSpacing(0); + CIQ_consoleLayout->setContentsMargins(0,0,0,0); + CIQ_consoleLayout->setAlignment(Qt::AlignTop); + } + +//公共方法 +public: + explicit Console(QWidget* parent = nullptr); + ~Console() { + } + + + void keyPressEvent(QKeyEvent *event) override { + //按键逻辑分支 + if (event->key() == Qt::Key_Return) { + QLineEdit* currentInput = qobject_cast(CIQ_consoleLayout->itemAt(CIQ_consoleLayout->count()-1)->widget()); + if (currentInput) { + currentInput->setReadOnly(true); + + // 创建新输入框并添加到布局 + QLineEdit* newInput = new QLineEdit(&CIQ_consoleWidget); + CIQ_consoleLayout->addWidget(newInput); + + // 设置新输入框焦点 + setFocusToCurrentInput(); + } + }//针对按下回车键之后的事件处理机制 + } + + void refreshAllStyleSheet(const Config& config) { + this->setStyleSheet(config.getCurrentConfig()+"QLineEdit{"+config.getCurrentConfig()+"};"); + CIQ_consoleWidget.setStyleSheet(config.getCurrentConfig()+"QLineEdit{"+config.getCurrentConfig()+"};"); + } + + void init(const Config& defaultConfig=Config(),const QSize& defaultSize=QSize()) { + initLayouts(); + + // 大小调整 + if (!defaultSize.isNull()) { + this->resize(defaultSize); + CIQ_scrollArea.resize(this->size()); + CIQ_consoleWidget.resize(this->size()); + } + + CIQ_consoleWidget.setLayout(CIQ_consoleLayout); + refreshAllStyleSheet(defaultConfig); + + // 添加初始输入框 + QLineEdit* initialInput = new QLineEdit(&CIQ_consoleWidget); + CIQ_consoleLayout->addWidget(initialInput); + + // 设置焦点 + setFocusToCurrentInput(); + + CIQ_scrollArea.setWidgetResizable(true); + CIQ_scrollArea.setWidget(&CIQ_consoleWidget); + + CIQ_mainLayout->addWidget(&CIQ_scrollArea); + CIQ_scrollArea.show(); + CIQ_consoleWidget.show(); + this->show(); + } + + inline void resizeEvent(QResizeEvent*) override{ + CIQ_consoleWidget.resize(this->size()); + } + +public slots: + // Shell Mode +}; + +} + // namespace ConsoleInQt +#endif // CONSOLE_H \ No newline at end of file diff --git a/ConsoleInQt_global.h b/ConsoleInQt_global.h new file mode 100644 index 0000000..69d72d0 --- /dev/null +++ b/ConsoleInQt_global.h @@ -0,0 +1,12 @@ +#ifndef CONSOLEINQT_GLOBAL_H +#define CONSOLEINQT_GLOBAL_H + +#include + +#if defined(CONSOLEINQT_LIBRARY) +# define CONSOLEINQT_EXPORT Q_DECL_EXPORT +#else +# define CONSOLEINQT_EXPORT Q_DECL_IMPORT +#endif + +#endif // CONSOLEINQT_GLOBAL_H From e52426510e016b3fe261127b3ca823ac388c0dc5 Mon Sep 17 00:00:00 2001 From: CCA8798 <2044187229@qq.com> Date: Thu, 25 Sep 2025 20:11:12 +0800 Subject: [PATCH 2/2] 25y27w02p v1.0 v1.0 First version --- Console.cpp | 5 ++ Console.h | 170 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 141 insertions(+), 34 deletions(-) diff --git a/Console.cpp b/Console.cpp index 3ad6197..1dc381a 100644 --- a/Console.cpp +++ b/Console.cpp @@ -2,4 +2,9 @@ using namespace ConsoleInQt; Console::Console(QWidget* parent) : QWidget(parent) { + CIQ_consoleWidget.setFocusPolicy(Qt::StrongFocus); + connect(CIQ_scrollArea.verticalScrollBar(),&QAbstractSlider::rangeChanged, [=]() { + CIQ_scrollArea.verticalScrollBar()->setValue(CIQ_scrollArea.verticalScrollBar()->maximum()); + }); + installEventFilter(this); } diff --git a/Console.h b/Console.h index 3e4760a..6fab56d 100644 --- a/Console.h +++ b/Console.h @@ -3,9 +3,12 @@ #include "ConsoleInQt_global.h" #include +#include #include #include +#include #include +#include #include #include #include @@ -63,48 +66,142 @@ public slots: } //测试输出 inline QString getCurrentConfig(void) const { - return QString("background: %1; color: %2; caret-color: %3; font-size: %4px; border-width: 0; border-style: outset;") - .arg(BackgroundColor, TextColor, TextCursorColor, TextSize); + return QString("background: %1; color: %2; font-size: %3px; border-width: 0; border-style: outset;") + .arg(BackgroundColor, TextColor, TextSize); } //获取当前全局设置 }; + +class Console; +class CONSOLEINQT_EXPORT ConsoleBufferStream { +private: + Console& console; + std::string buffer; +public: + explicit ConsoleBufferStream(Console& console):console(console){} + ConsoleBufferStream(const ConsoleBufferStream&)=delete; + ConsoleBufferStream& operator=(const ConsoleBufferStream&)=delete; + ConsoleBufferStream(ConsoleBufferStream&& other) noexcept + : console(other.console), buffer(std::move(other.buffer)) { + other.buffer.clear(); // 清空源对象缓冲区 + }; + inline ~ConsoleBufferStream(); + template + ConsoleBufferStream& operator<<(const BufferT& data) { + std::ostringstream oss; + oss<count() > 0) { - QWidget* lastWidget = CIQ_consoleLayout->itemAt(CIQ_consoleLayout->count()-1)->widget(); - if (lastWidget) { + if (QWidget* lastWidget = CIQ_consoleLayout->itemAt(CIQ_consoleLayout->count()-1)->widget()) { // 使用定时器确保在事件循环结束后设置焦点 - QTimer::singleShot(50, [lastWidget]() { + QTimer::singleShot(5, [lastWidget] { lastWidget->setFocus(); - if (QLineEdit* input = qobject_cast(lastWidget)) { + if (auto* input = qobject_cast(lastWidget)) { input->setCursorPosition(input->text().length()); } }); + //QThread::sleep(50); + /*lastWidget->setFocus(); + if (auto* input = qobject_cast(lastWidget)) { + input->setCursorPosition(input->text().length()); + }*/ + } + } + } + + void CIQ_Shell_createNewLine(const QString& content="",const bool userInput=true) { + QLineEdit* currentInput = nullptr; + if (CIQ_consoleLayout->count()>0) { + if ( (currentInput = qobject_cast(CIQ_consoleLayout->itemAt(CIQ_consoleLayout->count()-1)->widget()))) { + currentInput->setReadOnly(true); } } + auto* newInput = new QLineEdit(&CIQ_consoleWidget); + newInput->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + CIQ_currentLineEdit=newInput; + CIQ_consoleLayout->addWidget(newInput); + if (userInput) { + newInput->setText(">"+content); + connect(CIQ_currentLineEdit, &QLineEdit::textChanged, [this](){ + if (CIQ_currentLineEdit->text()[0]!=">") { + CIQ_currentLineEdit->setText(">"+CIQ_currentLineEdit->text()); + }}); + setFocusToCurrentInput(); + } + else { + newInput->setText(content); + newInput->setReadOnly(true); + } } //初始化主布局和控制台窗口布局 void initLayouts(void) { + CIQ_consoleWidget.setLayout(CIQ_consoleLayout); CIQ_mainLayout->setMargin(0); CIQ_mainLayout->setSpacing(0); CIQ_mainLayout->setContentsMargins(0,0,0,0); - CIQ_mainLayout->setAlignment(Qt::AlignTop); + CIQ_mainLayout->setAlignment(Qt::AlignCenter); CIQ_consoleLayout->setMargin(0); CIQ_consoleLayout->setSpacing(0); CIQ_consoleLayout->setContentsMargins(0,0,0,0); - CIQ_consoleLayout->setAlignment(Qt::AlignTop); + CIQ_consoleLayout->setAlignment(Qt::AlignTop|Qt::AlignLeft); + } + + bool eventFilter(QObject *watched, QEvent *event) override { + if (static_cast(event)->key()&&CIQ_currentLineEdit!=nullptr&&CIQ_currentLineEdit->cursorPosition()<=1) { + CIQ_currentLineEdit->setCursorPosition(1); + } + return QWidget::eventFilter(watched, event); + } + + void keyPressEvent(QKeyEvent *event) override { + //按键逻辑分支 + if (event->key() == Qt::Key_Return) { + emit commandSend(std::string_view(std::string(std::string(CIQ_currentLineEdit->text().toStdString()).begin()+1,std::string(CIQ_currentLineEdit->text().toStdString()).end()))); + QString command=""; + for (int i=1;itext().length();i++) { + command+=CIQ_currentLineEdit->text()[i]; + } + emit commandSend(command); + CIQ_Shell_createNewLine(); + return; + }//针对按下回车键之后的事件处理机制 + if (event->key()&&CIQ_currentLineEdit!=nullptr&&CIQ_currentLineEdit->cursorPosition()<=1) { + CIQ_currentLineEdit->setCursorPosition(1); + } + } +protected: + void processBuffer(const std::string& buffer) { + std::istringstream iss(buffer); + std::string line; + while (std::getline(iss, line)) { + CIQ_Shell_createNewLine(QString::fromStdString(line), false); + } + CIQ_Shell_createNewLine(); } //公共方法 @@ -113,22 +210,25 @@ class CONSOLEINQT_EXPORT Console : public QWidget ~Console() { } + template // 默认以string_view构建 + ConsoleBufferStream operator<<(OutputT&& content) { + ConsoleBufferStream bufferStream(*this); - void keyPressEvent(QKeyEvent *event) override { - //按键逻辑分支 - if (event->key() == Qt::Key_Return) { - QLineEdit* currentInput = qobject_cast(CIQ_consoleLayout->itemAt(CIQ_consoleLayout->count()-1)->widget()); - if (currentInput) { - currentInput->setReadOnly(true); - - // 创建新输入框并添加到布局 - QLineEdit* newInput = new QLineEdit(&CIQ_consoleWidget); - CIQ_consoleLayout->addWidget(newInput); + if constexpr(std::is_same_v, QString>) { + bufferStream << content.toStdString(); + } + else if constexpr(std::is_convertible_v) { + // 处理所有可转换为string_view的类型(包括string、char数组等) + bufferStream << std::string_view(content); + } + else { + // 回退到ostream处理(如数值类型) + std::ostringstream oss; + oss << content; + bufferStream << oss.str(); + } - // 设置新输入框焦点 - setFocusToCurrentInput(); - } - }//针对按下回车键之后的事件处理机制 + return bufferStream; } void refreshAllStyleSheet(const Config& config) { @@ -138,27 +238,24 @@ class CONSOLEINQT_EXPORT Console : public QWidget void init(const Config& defaultConfig=Config(),const QSize& defaultSize=QSize()) { initLayouts(); - // 大小调整 if (!defaultSize.isNull()) { this->resize(defaultSize); CIQ_scrollArea.resize(this->size()); CIQ_consoleWidget.resize(this->size()); } - - CIQ_consoleWidget.setLayout(CIQ_consoleLayout); refreshAllStyleSheet(defaultConfig); // 添加初始输入框 - QLineEdit* initialInput = new QLineEdit(&CIQ_consoleWidget); - CIQ_consoleLayout->addWidget(initialInput); - - // 设置焦点 - setFocusToCurrentInput(); + if (!defaultConfig.getWelcomeMessage().isEmpty()) { + *this<addWidget(&CIQ_scrollArea); CIQ_scrollArea.show(); CIQ_consoleWidget.show(); @@ -173,6 +270,11 @@ public slots: // Shell Mode }; +inline ConsoleBufferStream::~ConsoleBufferStream() { + console.processBuffer(buffer); +} + + } // namespace ConsoleInQt #endif // CONSOLE_H \ No newline at end of file