add an example to embed a server in a Qt GUI app

This commit is contained in:
Chunting Gu
2021-01-22 11:34:17 +08:00
parent c3643277b2
commit 233aa5910c
7 changed files with 132 additions and 4 deletions
+7 -3
View File
@@ -40,10 +40,14 @@ target_link_libraries(form_urlencoded_client ${EXAMPLE_LIBS})
add_executable(form_server form_server.cc)
target_link_libraries(form_server ${EXAMPLE_LIBS})
add_subdirectory(book_server)
add_subdirectory(book_client)
if(WIN32)
add_executable(url_unicode url_unicode.cc encoding.cc encoding.h)
target_link_libraries(url_unicode ${EXAMPLE_LIBS})
endif()
add_subdirectory(book_server)
add_subdirectory(book_client)
if(WEBCC_ENABLE_QT_EXAMPLES)
add_subdirectory(qt_app_server)
endif()
+11
View File
@@ -0,0 +1,11 @@
project(qt_app_server)
find_package(Qt5 CONFIG REQUIRED Core Gui Widgets)
set(CMAKE_AUTOMOC ON)
file(GLOB SRCS *.cpp *.h)
add_executable(qt_app_server ${SRCS})
target_link_libraries(qt_app_server Qt5::Core Qt5::Gui Qt5::Widgets ${EXAMPLE_LIBS})
+56
View File
@@ -0,0 +1,56 @@
#include <thread>
#include <QApplication>
#include "examples/qt_app_server/main_window.h"
#include "webcc/logger.h"
#include "webcc/response_builder.h"
#include "webcc/server.h"
#include "webcc/view.h"
class ApiView : public webcc::View {
public:
explicit ApiView(Context* context) : context_(context) {
}
webcc::ResponsePtr Handle(webcc::RequestPtr request) override {
if (request->method() == "GET") {
emit context_->SomeApiSignal("A GET request has been handled");
return webcc::ResponseBuilder{}.OK().Body("Hello, World!")();
}
return {};
}
private:
Context* context_;
};
int main(int argc, char** argv) {
QApplication app{ argc, argv };
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
Context context;
// Create a server and bind view.
webcc::Server server{ boost::asio::ip::tcp::v4(), 8000 };
server.Route("/", std::make_shared<ApiView>(&context));
// Run the server in a thread to avoid blocking the GUI.
std::thread server_thread{ [&server]() { server.Run(); } };
// Now show our Qt main window and execute the application loop.
MainWindow main_window{ &context };
main_window.resize(400, 300);
main_window.showNormal();
int code = app.exec();
// Stop the server and wait for it to finish.
server.Stop();
server_thread.join();
return code;
}
+21
View File
@@ -0,0 +1,21 @@
#include "examples/qt_app_server/main_window.h"
#include <QDebug>
MainWindow::MainWindow(Context* context, QWidget* parent)
: QMainWindow(parent) {
setWindowTitle("Qt App Server");
#if 1
connect(context, &Context::SomeApiSignal, this, &MainWindow::OnSomeApiSignal);
#else
// NOTE: Seems not necessary to use QueuedConnection (because we are using
// std::thread instead of QThread?).
connect(context, &Context::SomeApiSignal, this, &MainWindow::OnSomeApiSignal,
Qt::QueuedConnection);
#endif
}
void MainWindow::OnSomeApiSignal(const QString& text) {
qDebug() << text;
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef MAIN_WINDOW_H_
#define MAIN_WINDOW_H_
#include <QMainWindow>
// Some global QObject with public signals for ApiView to inform the handling
// of client requests.
// "Context" is a bad name, you should change it.
class Context : public QObject {
Q_OBJECT
public:
explicit Context(QObject* parent = nullptr) : QObject(parent) {
}
// Public signals emitted from ApiView:
signals:
void SomeApiSignal(const QString& text);
// Add other signals here...
};
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(Context* context, QWidget* parent = nullptr);
private:
// You should encapsulate the required information as the signal parameters.
// I use QString just for demostrating how to transfer data from ApiView.
void OnSomeApiSignal(const QString& text);
};
#endif // MAIN_WINDOW_H_