📜 ⬆️ ⬇️

We write a website with news on Wt

To begin, tell a little about yourself. I am a 4th year student of the MAI majoring in “Computers, Complexes, Systems and Networks”, as well as a novice C ++ / Qt programmer. A long time ago I wanted to learn web development, but my hands didn’t get to learn all the necessary languages ​​and technologies. Recently on Habré an article appeared on the creation of web applications using the C ++ library Wt , and I decided to get acquainted with this library.

Workplace preparation


I wrote all the code under Gentoo-linux in Qt Creator. If you decide to do the same, then you first have to prepare the environment for our needs.
The first thing to do is create a project. I used “Simple C ++ Project” without Qt support. Although Wt can be used in conjunction with Qt, in this case, we will not need it.


I called the project MyApp. Next, open the file MyApp.pro and edit it a little. Namely, in my case, you need to add the following lines:

LIBS + = -L / usr / lib -lwt -lwthttp -lwtdbo -lwtdbosqlite3 -I / usr / local / include
LIBS + = -L / usr / local / lib -lwthttp -lwt -lboost_regex -lboost_signals
LIBS + = -lboost_system -lboost_thread -lboost_filesystem -lboost_date_time -lpthread -lcrypt

')
We will also need to link the resources folder to the place from which we will launch our website. For example:
ln -s /usr/share/Wt/resources/ ~/build-MyApp-Qt5-/

Preparation on this can be considered complete.

So, let's begin...


To run an empty application, it is enough to write this code:
 #include <iostream> #include <Wt/WServer> #include <Wt/WApplication> using namespace Wt; WApplication *createWidget(const WEnvironment& env) { WApplication *app=new WApplication(env); //  - app->setTitle("My Site"); //   ( ,   html <title></title>) app->setTheme(new Wt::WBootstrapTheme()); //   bootstrap return app; } int main(int argc, char **argv) { Wt::WServer server(argv[0]); //  server.setServerConfiguration(argc, argv, WTHTTP_CONFIGURATION); //  server.addEntryPoint(Wt::Application,createWidget); // " " if (server.start()) { int sig = Wt::WServer::waitForShutdown(); // ,   std::cerr << "Shutting down: (signal = " << sig << ")" << std::endl; server.stop(); } } 


We can run all this on localhost on port 8080 with the command:

./myapp --docroot . --http-address 0.0.0.0 --http-port 8080

The startup process can be automated; for this, the startup parameters must be entered in the line “Projects-> Start-> Parameters”



Thus, we get a web server with a blank page, which can be accessed at localhost:8080/

Add a menu.


Let's start filling. To begin with we will make the menu for our site. To do this, create a new class, I called it "Page".
page.h:

 #ifndef PAGE_H #define PAGE_H #include <Wt/WContainerWidget> #include <Wt/WText> #include <Wt/WString> #include <Wt/WNavigationBar> #include <Wt/WMenu> #include <Wt/WStackedWidget> class Page : public Wt::WContainerWidget { public: Page(WContainerWidget *parent = 0); private: Wt::WStackedWidget *contentsStack; Wt::WNavigationBar *NavBar; Wt::WMenu *LeftMenu; }; #endif // PAGE_H 


page.cpp:

 #include "page.h" using namespace Wt; Page::Page(WContainerWidget *parent):WContainerWidget(parent) { setStyleClass("container"); contentsStack = new Wt::WStackedWidget(); //  ""   ,     contentsStack->setStyleClass("container"); contentsStack->setPadding(48,Wt::Top); //,           "" NavBar = new WNavigationBar(this); //   NavBar->setTitle("MyApp","http://localhost:8080"); //    ,    NavBar->setResponsive(true); //       NavBar->addStyleClass("container"); // bootstrap NavBar->setPositionScheme(Wt::Fixed); //    LeftMenu=new WMenu(contentsStack,this); //  . ,    . NavBar->addMenu(LeftMenu); //     LeftMenu->addItem(WString::fromUTF8(""),new WText(WString::fromUTF8("  "))); //    "". addWidget(contentsStack); //    ,     ,    -  . } 


At the same time you need to add a line to main.cpp

 ... WApplication *createWidget(const WEnvironment& env) { WApplication *app=new WApplication(env); app->setTitle("My Site"); app->setTheme(new Wt::WBootstrapTheme()); new Page(app->root()); // ! return app; } ... 


Checking:



Let's say. And where is the news?


Now we will reach them. First we need to learn how to work with the database.
In Wt, working with the database, as for me, is implemented rather strangely, but when I figured out the principle, I no longer had any particular problems or difficulties.

The first thing you need is to create our news template as a class.

news.h:

 #ifndef NEWS_H #define NEWS_H #include <Wt/WDateTime> #include <Wt/Dbo/Types> #include <Wt/Dbo/WtSqlTraits> class News { public: News(); std::string title; //  std::string text; //  std::string author; //  Wt::WDateTime created; //  template<class Action> //       void persist(Action& a) { Wt::Dbo::field(a, title, "title"); Wt::Dbo::field(a, text, "text"); Wt::Dbo::field(a, author, "aurhor"); Wt::Dbo::field(a, created, "created"); } }; DBO_EXTERN_TEMPLATES(News); #endif // NEWS_H 

news.cpp:
 #include "news.h" #include <Wt/Dbo/Impl> DBO_INSTANTIATE_TEMPLATES(News); News::News(): created(Wt::WDateTime::currentDateTime()) //   ,  ,      . {} 


“Hmm, and how to use it?” - you ask. Everything is very simple. I used sqlite3 for some reason (portability with the project and because MySQL support for Wt was not collected for unknown reasons), but it should work similarly with any supported database.

Rewrite page.cpp:

 #include "page.h" #include "news.h" #include <Wt/Dbo/backend/Sqlite3> #include <Wt/WApplication> #include <Wt/WPanel> using namespace Wt; Page::Page(WContainerWidget *parent):WContainerWidget(parent) { Wt::Dbo::backend::Sqlite3 DataBase=WApplication::instance()->appRoot() + "myapp.db"; //   Wt::Dbo::Session DBSession; //  DBSession.setConnection(DataBase); // DBSession.mapClass<News>("news"); //     news   Wt::Dbo::Transaction transaction(DBSession); //  try { DBSession.createTables(); //     ,      .     . Wt::log("info") << "Database created"; } catch (...) { Wt::log("info") << "Using existing database"; } transaction.commit();//  Wt::WTable *NewsTable=new Wt::WTable();//     NewsTable->addStyleClass("container");//    Wt::Dbo::Transaction transaction1(DBSession);//  .       ,   . Wt::Dbo::collection<Wt::Dbo::ptr<News> > a=DBSession.find<News>().orderBy("created desc");//    ,      . int j=0; for (Wt::Dbo::collection<Wt::Dbo::ptr<News> >::const_iterator i = a.begin(); i != a.end(); ++i) {//  .       ,        .   =) Wt::Dbo::ptr<News> Article = *i; Wt::WPanel *panel = new Wt::WPanel(); panel->setTitle(Article.get()->title); panel->setCentralWidget(new Wt::WText(WString::fromUTF8("<p>:")+Article.get()->author+"</p><p>"+Article.get()->text+"</p>")); NewsTable->elementAt(j,0)->addWidget(panel); j++; } transaction1.commit();// . ,    . setStyleClass("container"); contentsStack = new Wt::WStackedWidget(); contentsStack->setStyleClass("container"); contentsStack->setPadding(48,Wt::Top); NavBar = new WNavigationBar(this); NavBar->setTitle("MyApp","http://cursed.redegrade.net"); NavBar->setResponsive(true); NavBar->addStyleClass("container"); NavBar->setPositionScheme(Wt::Fixed); LeftMenu=new WMenu(contentsStack,this); NavBar->addMenu(LeftMenu); LeftMenu->addItem(WString::fromUTF8(""),NewsTable); //       . this->addWidget(contentsStack); } 


Well, about the output of news, everything is clear, but what about the creation?


Hmm, really. Where without creation. Now fasten. We'll have to rewrite the Page class again, the final one within the article.

page.h:

 #ifndef PAGE_H #define PAGE_H #include <Wt/WContainerWidget> #include <Wt/WText> #include <Wt/WString> #include <Wt/WNavigationBar> #include <Wt/WMenu> #include <Wt/WTable> #include <Wt/WStackedWidget> #include <Wt/Dbo/Session> class Page : public Wt::WContainerWidget { public: Page(WContainerWidget *parent = 0); private: Wt::WStackedWidget *contentsStack; Wt::WNavigationBar *NavBar; Wt::WMenu *LeftMenu; Wt::WTable *CreateArticle; Wt::WLineEdit *Title; Wt::WLineEdit *Author; Wt::WTextArea *Text; Wt::WPushButton *AddNews; Wt::Dbo::Session DBSession; void AddArticle(); }; #endif // PAGE_H 


page.cpp

 #include "page.h" #include "news.h" #include <Wt/WApplication> #include <Wt/WPanel> #include <Wt/WLineEdit> #include <Wt/WTextEdit> #include <Wt/WPushButton> #include <Wt/Dbo/backend/Sqlite3> using namespace Wt; Page::Page(WContainerWidget *parent):WContainerWidget(parent) { Wt::Dbo::backend::Sqlite3 DataBase=WApplication::instance()->appRoot() + "myapp.db"; DBSession.setConnection(DataBase); DBSession.mapClass<News>("news"); Wt::Dbo::Transaction transaction(DBSession); try { DBSession.createTables(); Wt::log("info") << "Database created"; } catch (...) { Wt::log("info") << "Using existing database"; } transaction.commit(); Wt::WTable *NewsTable=new Wt::WTable(); NewsTable->addStyleClass("container"); Wt::Dbo::Transaction transaction1(DBSession); Wt::Dbo::collection<Wt::Dbo::ptr<News> > a=DBSession.find<News>().orderBy("created desc"); int j=0; for (Wt::Dbo::collection<Wt::Dbo::ptr<News> >::const_iterator i = a.begin(); i != a.end(); ++i) { Wt::Dbo::ptr<News> Article = *i; Wt::WPanel *panel = new Wt::WPanel(); panel->setTitle(WString::fromUTF8(Article.get()->title)); panel->setCentralWidget(new Wt::WText(WString::fromUTF8("<p>:")+WString::fromUTF8(Article.get()->author)+"</p><p>"+WString::fromUTF8(Article.get()->text)+"</p>"));//  .        . NewsTable->elementAt(j,0)->addWidget(panel); NewsTable->elementAt(j,0)->setLoadLaterWhenInvisible(true); j++; } transaction1.commit(); setStyleClass("container"); contentsStack = new Wt::WStackedWidget(); contentsStack->setStyleClass("container"); contentsStack->setPadding(48,Wt::Top); NavBar = new WNavigationBar(this); NavBar->setTitle("MyApp","http://localhost:8080"); NavBar->setResponsive(true); NavBar->addStyleClass("container"); NavBar->setPositionScheme(Wt::Fixed); LeftMenu=new WMenu(contentsStack,this); NavBar->addMenu(LeftMenu); LeftMenu->addItem(WString::fromUTF8(""),NewsTable); CreateArticle=new Wt::WTable(); //     Title=new Wt::WLineEdit(WString::fromUTF8(" ")); //  Author=new Wt::WLineEdit(WString::fromUTF8("")); Text=new Wt::WTextArea(WString::fromUTF8(" ")); AddNews=new Wt::WPushButton(WString::fromUTF8(" ")); CreateArticle->addStyleClass("container"); CreateArticle->elementAt(0,0)->addWidget(Title); //    CreateArticle->elementAt(1,0)->addWidget(Author); CreateArticle->elementAt(2,0)->addWidget(Text); CreateArticle->elementAt(3,0)->addWidget(AddNews); LeftMenu->addItem(WString::fromUTF8(" "),CreateArticle); //     Page::AddArticle    AddNews->clicked().connect(this,&Page::AddArticle); this->addWidget(contentsStack); } void Page::AddArticle() { Wt::Dbo::backend::Sqlite3 DataBase=WApplication::instance()->appRoot() + "myapp.db"; DBSession.setConnection(DataBase); // (   , ,     ,   ) Wt::Dbo::Transaction transaction(DBSession); //:        . News *a=new News(); //  a->title=Title->text().toUTF8(); a->author=Author->text().toUTF8(); a->text=Text->text().toUTF8(); Wt::Dbo::ptr<News> Article=DBSession.add(a); //    } 


Result:




PS If you need additional explanations, write in the comments, I will try to tell you more. I just started to learn Wt, so it is quite possible that somewhere is wrong. I would be glad if you correct.
PPS If you are interested in articles on Wt, write in the comments what else you would like to know about it, and I will try to write about it!

Source: https://habr.com/ru/post/209754/


All Articles