This error is with wxWidgets 3.1.5, and SFML 2.5.1
I have the following code:
(main.cpp) :-
#include <SFML/Graphics.hpp>
#include <wx/wx.h>
#include "wxSfmlCanvas.h"
#include "main.h"
TestFrame::TestFrame() :
wxFrame(NULL, wxID_ANY, "SFML 2.5 w/ wxWidgets 3.1", wxDefaultPosition, wxSize(650, 490))
{
mCanvas = new TestSfmlCanvas(this, wxID_ANY, wxPoint(5, 25), wxSize(640, 480));
// Also add a button.
wxButton *button = new wxButton(
this,
wxID_ANY,
wxT("Toggle Size"),
wxPoint(5, 5)
);
button->Bind(wxEVT_BUTTON, [&](wxCommandEvent& arg) -> void {
mCanvas->toggleSize();
});
wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
mainSizer->Add(mCanvas, 6, wxALIGN_TOP | wxEXPAND);
mainSizer->Add(button, 0, wxALIGN_RIGHT | wxALIGN_BOTTOM);
SetSizerAndFit(mainSizer);
}
TestSfmlCanvas::TestSfmlCanvas(
wxWindow* Parent,
wxWindowID Id,
wxPoint& Position,
wxSize& Size,
long Style
) : wxSfmlCanvas(Parent, Id, Position, Size, Style),
mLarge(false)
{
// Load a texture and create a sprite.
mTexture.loadFromFile("data/ball.png");
mSprite = std::make_unique<sf::Sprite>(mTexture);
}
void
TestSfmlCanvas::OnUpdate()
{
clear(sf::Color(64, 196, 196));
draw(*mSprite);
}
void
TestSfmlCanvas::toggleSize()
{
if (mLarge) {
mSprite->setScale(sf::Vector2f(1.2f, 1.2f));
}
else {
mSprite->setScale(sf::Vector2f(0.5f, 0.5f));
}
mLarge = !mLarge;
}
IMPLEMENT_APP(TestApplication);
(and main.h) :-
#pragma once
#include <memory>
#include <SFML/Graphics.hpp>
#include <wx/wx.h>
#include <string>
#include "wxSfmlCanvas.h"
// Our overridden class that does some SFML drawing.
class TestSfmlCanvas : public wxSfmlCanvas
{
public:
TestSfmlCanvas(
wxWindow* Parent,
wxWindowID Id,
wxPoint& Position,
wxSize& Size,
long Style = 0
);
void toggleSize();
protected:
void OnUpdate() override;
private:
sf::Texture mTexture;
std::unique_ptr<sf::Sprite> mSprite;
bool mLarge;
};
// wx Frame to contain the main canvas control. Can have extra controls added to it as desired.
class TestFrame : public wxFrame
{
public :
TestFrame();
protected:
TestSfmlCanvas* mCanvas;
};
// Main wx Application instance.
class TestApplication : public wxApp
{
private :
virtual bool OnInit()
{
// Create the main window
TestFrame* MainFrame = new TestFrame;
MainFrame->Show();
return true;
}
};
(wxSFMLCanvas.h) :-
#pragma once
#include <SFML/Graphics.hpp>
#include <wx/wx.h>
#include <string>
class wxSfmlCanvas : public wxControl, public sf::RenderWindow
{
public:
wxSfmlCanvas(wxWindow* Parent = nullptr,
wxWindowID Id = -1,
//const wxPoint& Position = wxDefaultPosition,
const wxSize& Size = wxDefaultSize,
long Style = 0);
virtual ~wxSfmlCanvas();
protected:
virtual void OnUpdate();
void OnIdle(wxIdleEvent&);
void OnPaint(wxPaintEvent&);
void OnEraseBackground(wxEraseEvent&);
void OnSize(wxSizeEvent&);
DECLARE_EVENT_TABLE()
};
(wxSFMLCanvas.cpp) :-
#include "wxSfmlCanvas.h"
#include <wx/wx.h>
#include <string>
BEGIN_EVENT_TABLE(wxSfmlCanvas, wxControl)
EVT_PAINT(wxSfmlCanvas::OnPaint)
EVT_IDLE(wxSfmlCanvas::OnIdle)
EVT_ERASE_BACKGROUND(wxSfmlCanvas::OnEraseBackground)
EVT_SIZE(wxSfmlCanvas::OnSize)
END_EVENT_TABLE()
#ifdef __WXGTK__
#include <string>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#include <wx/gtk/win_gtk.h>
#endif
wxSfmlCanvas::wxSfmlCanvas(wxWindow* Parent,
wxWindowID Id,
const wxPoint& Position,
const wxSize& Size,
long Style) :
wxControl(Parent, Id, Position, Size, Style)
{
#ifdef __WXGTK__
#else
sf::RenderWindow::create(GetHandle());
#endif
}
void wxSfmlCanvas::OnIdle(wxIdleEvent&)
{
// Send a paint message when the control is idle, to ensure maximum framerate
Refresh();
}
wxSfmlCanvas::~wxSfmlCanvas()
{
}
void wxSfmlCanvas::OnUpdate()
{
}
void wxSfmlCanvas::OnEraseBackground(wxEraseEvent&)
{
}
void wxSfmlCanvas::OnSize(wxSizeEvent& args)
{
// Set the size of the sfml rendering window
setSize(sf::Vector2u(args.GetSize().x, args.GetSize().y));
// Also adjust the viewport so that a pixel stays 1-to-1.
setView(sf::View(sf::FloatRect(0, 0, args.GetSize().x, args.GetSize().y)));
}
void wxSfmlCanvas::OnPaint(wxPaintEvent&)
{
// Prepare the control to be repainted
wxPaintDC Dc(this);
// Let the derived class do its specific stuff
OnUpdate();
// Display on screen
display();
}
With this code, I get the following compile errors:
Severity Code Description Project File Line Suppression State Error C4996 '_wgetenv': This function or variable may be unsafe. Consider using _wdupenv_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. ae D:\wxwidg\include\wx\wxcrt.h 1050
And 100 similar others.
Why? what did I do wrong for this?
wxWidgets is properly built, SFML and wx work fine on their own, but when combined, this error takes place for some reason.
The messages you show are not errors at all, they are static analyser warnings and can be safely ignored, the "unsafe" functions are not used in unsafe way inside wxWidgets.
Related
I have made an application using wxWidgets 3.1.5 in C++ and everything is working fine except a test button that I have on my main window.
Here's a pic:
The menubar, menus and their functions work perfectly but the button covers the entire client area.
Here's the code:
main.h
#pragma once
#include <wx\wx.h>
#include "mainFrame.h"
class main : public wxApp
{
private:
mainFrame* frame;
public:
virtual bool OnInit();
};
main.cpp
#include "main.h"
wxIMPLEMENT_APP(main);
bool main::OnInit()
{
frame = new mainFrame("Kill Me", wxPoint(15, 10), wxSize(640, 480));
frame->Show();
return true;
}
mainFrame.h
#pragma once
#include "About.h"
using str = std::string;
class mainFrame : public wxFrame
{
public:
mainFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
~mainFrame();
private:
About* abtF = NULL;
wxButton* hewwo = NULL;
wxMenuBar* mbar = NULL;
wxMenu* sett = NULL;
wxMenu* quitApp = NULL;
wxMenu* abt = NULL;
void onHewwo(wxCommandEvent& evt);
void onSett(wxCommandEvent& evt);
void quit(wxCommandEvent& evt);
void about(wxCommandEvent& evt);
wxDECLARE_EVENT_TABLE();
};
enum {
ID_SETT = 1,
ID_BTN = 2
};
mainFrame.cpp
#include "mainFrame.h"
wxBEGIN_EVENT_TABLE(mainFrame, wxFrame)
EVT_BUTTON(ID_BTN, onHewwo)
EVT_MENU(ID_SETT, onSett)
EVT_MENU(wxID_EXIT, quit)
EVT_MENU(wxID_ABOUT, about)
wxEND_EVENT_TABLE()
mainFrame::mainFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
:
wxFrame(nullptr, wxID_ANY, title, pos, size) {
hewwo = new wxButton(this, ID_BTN, "Hewwo World", wxPoint(15, 15), wxSize(70, 20));
sett = new wxMenu();
sett->AppendSeparator();
sett->Append(ID_SETT, "&Settings");
quitApp = new wxMenu();
quitApp->AppendSeparator();
quitApp->Append(wxID_EXIT, "&Quit this crap");
abt = new wxMenu();
abt->AppendSeparator();
abt->Append(wxID_ABOUT, "&About");
mbar = new wxMenuBar();
mbar->Append(sett, "&Settings");
mbar->Append(abt, "&About");
mbar->Append(quitApp, "&Quit");
SetMenuBar(mbar);
}
void mainFrame::onHewwo(wxCommandEvent& evt) {
wxMessageBox("Hewwo", "Hewwo", wxOK | wxICON_INFORMATION, this);
}
void mainFrame::onSett(wxCommandEvent& evt) {
wxMessageBox("Settings", "Settings", wxOK | wxICON_INFORMATION, this); // Just a test
}
void mainFrame::about(wxCommandEvent& evt) {
abtF = new About(wxPoint(10, 10), wxSize(480, 320));
abtF->Show();
}
void mainFrame::quit(wxCommandEvent& evt) {
Close(true);
}
mainFrame::~mainFrame() {
delete abtF;
}
I'm using Visual Studio 2019.
(I followed OneLoneCoder's (javidx9) youtube video on wxWidgets)
That is how a wxFrame with only one child behaves.
If you don't want that, use a wxSizer to layout your button (position, align, expand etc).
Reference:
if the frame has exactly one child window, not counting the status and toolbar, this child is resized to take the entire frame client area. If two or more windows are present, they should be laid out explicitly either by manually handling wxEVT_SIZE or using sizers
wxFrame docs -> Default event processing -> wxEVT_SIZE
I am trying to create a simple program with a menu using wxWidgets. However, the menu doesn't seem to be appearing properly.
This is my code:
helloworld.hpp:
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "TextFrame.hpp"
class HelloWorldApp : public wxApp {
public:
virtual bool OnInit();
};
DECLARE_APP(HelloWorldApp)
helloworld.cpp:
#include "helloworld.hpp"
IMPLEMENT_APP(HelloWorldApp)
bool HelloWorldApp::OnInit() {
TextFrame *frame = new TextFrame(_T("Hi"), 200, 200, 800, 600);
frame->CreateStatusBar();
frame->SetStatusText(_T("Hello, World!"));
frame->Show(true);
SetTopWindow(frame);
return true;
}
TextFrame.hpp:
#pragma once
#include <wx/wxprec.h>
#ifndef WX_PREC
#include <wx/wx.h>
#endif
class TextFrame : public wxFrame {
public:
/** Constructor. Creates a new TextFrame */
TextFrame(const wxChar *title, int xpos, int ypos, int width, int height);
private:
wxTextCtrl *m_pTextCtrl;
wxMenuBar *m_pMenuBar;
wxMenu *m_pFileMenu;
wxMenu *m_pHelpMenu;
};
TextFrame.cpp:
#include "TextFrame.hpp"
TextFrame::TextFrame(const wxChar *title, int xpos, int ypos, int width, int height)
: wxFrame((wxFrame *) NULL, -1, title, wxPoint(xpos, ypos), wxSize(width, height))
{
m_pTextCtrl = new wxTextCtrl(this, -1, _T("Type some text..."),
wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
m_pMenuBar = new wxMenuBar();
// File Menu
m_pFileMenu = new wxMenu();
m_pFileMenu->Append(wxID_OPEN, _T("&Open"));
m_pFileMenu->Append(wxID_SAVE, _T("&Save"));
m_pFileMenu->AppendSeparator();
m_pFileMenu->Append(wxID_EXIT, _T("&Quit"));
m_pMenuBar->Append(m_pFileMenu, _T("&File"));
// About menu
m_pHelpMenu = new wxMenu();
m_pHelpMenu->Append(wxID_ABOUT, _T("&About"));
m_pMenuBar->Append(m_pHelpMenu, _T("&Help"));
SetMenuBar(m_pMenuBar);
}
This code comes (for the most part) directly from here.
It compiles successfully (using g++ TextFrame.cpp helloworld.cpp `wx-config -cxxflags --libs` -o helloworld), but when I run it I see the default menu, and not the custom one I tried to add.
I tried out the "menu" sample and that works fine, so I think I'm doing something wrong here.
Thank you for your help.
I am a novice in C++ and wxWidgets, and use wxFormBuilder to help me create the GUI.
I like the idea to put similar functions together in 1 module, which means that my apps have multiple modules.
One of the modules is for the GUI (it now contains code for the main Frame (with only a menu and taskbar) and
a Panel (with 2 StaticText controls and a button).
The button increments a counter and the value is shown in one of the StaticTexts on the Panel.
Sofar so good. (compiles without errors)
I can make the Panel show/Hide, but I seem to miss an essential piece of knowledge to make the Panel button work.
The ways I tried are all similar to the way the Main module is coded, but that is not working.
I understand how it works with GUI class elements in the same file.
However, I like to keep all GUI code in one module (GUIFrame.h/.cpp),
and all the 'function' code in e.g. the Panel module (MyPanel.h/.cpp).
Just because I am not sure where I make my mistake, I present all code in this post.
My aplologies if it is too much.
Hopefully someone can help me bridge my gap in knowledge about this way of working.
Regards,
Ruud
=== GUIFrame.h
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/string.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/menu.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/statusbr.h>
#include <wx/frame.h>
#include <wx/stattext.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/panel.h>
///////////////////////////////////////////////////////////////////////////
#define idMenuQuit 1000
///////////////////////////////////////////////////////////////////////////////
/// Class GUIFrame
///////////////////////////////////////////////////////////////////////////////
class GUIFrame : public wxFrame
{
private:
protected:
wxMenuBar* mbar;
wxMenu* mainMenu;
wxStatusBar* statusBar;
// Virtual event handlers, overide them in your derived class
virtual void OnClose( wxCloseEvent& event ) { event.Skip(); }
virtual void m_menuItemPanelMainOnMenuSelection( wxCommandEvent& event ) { event.Skip(); }
virtual void OnQuit( wxCommandEvent& event ) { event.Skip(); }
public:
GUIFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("Test application"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 500,500 ), long style = wxDEFAULT_FRAME_STYLE );
~GUIFrame();
};
///////////////////////////////////////////////////////////////////////////////
/// Class PanelMAIN
///////////////////////////////////////////////////////////////////////////////
class PanelMAIN : public wxPanel
{
private:
protected:
wxStaticText* m_staticText3;
// Virtual event handlers, overide them in your derived class
virtual void m_btn_Counter_OnButtonClick( wxCommandEvent& event ) { event.Skip(); }
public:
wxStaticText* m_staticTextPMain;
wxButton* m_buttonPMain;
PanelMAIN( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxPoint( 3,3 ), const wxSize& size = wxSize( 350,300 ), long style = wxBORDER_RAISED, const wxString& name = wxEmptyString );
~PanelMAIN();
};
==== GUIFrame.cpp
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif //WX_PRECOMP
#include "GUIFrame.h"
///////////////////////////////////////////////////////////////////////////
GUIFrame::GUIFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
mbar = new wxMenuBar( 0 );
mainMenu = new wxMenu();
wxMenuItem* m_menuItemPanelMain;
m_menuItemPanelMain = new wxMenuItem( mainMenu, wxID_ANY, wxString( wxT("To Main Panel") ) , wxEmptyString, wxITEM_NORMAL );
mainMenu->Append( m_menuItemPanelMain );
wxMenuItem* menuFileQuit;
menuFileQuit = new wxMenuItem( mainMenu, idMenuQuit, wxString( wxT("&Quit") ) + wxT('\t') + wxT("Alt+F4"), wxT("Quit the application"), wxITEM_NORMAL );
mainMenu->Append( menuFileQuit );
mbar->Append( mainMenu, wxT("&Menu") );
this->SetMenuBar( mbar );
statusBar = this->CreateStatusBar( 2, wxSTB_SIZEGRIP, wxID_ANY );
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( GUIFrame::OnClose ) );
mainMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GUIFrame::m_menuItemPanelMainOnMenuSelection ), this, m_menuItemPanelMain->GetId());
mainMenu->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( GUIFrame::OnQuit ), this, menuFileQuit->GetId());
}
GUIFrame::~GUIFrame()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( GUIFrame::OnClose ) );
}
PanelMAIN::PanelMAIN( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : wxPanel( parent, id, pos, size, style, name )
{
this->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_APPWORKSPACE ) );
wxBoxSizer* bSizer1;
bSizer1 = new wxBoxSizer( wxVERTICAL );
m_staticTextPMain = new wxStaticText( this, wxID_ANY, wxT("We are on PanelMAIN now"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextPMain->Wrap( -1 );
bSizer1->Add( m_staticTextPMain, 0, wxALL, 5 );
m_buttonPMain = new wxButton( this, wxID_ANY, wxT("Counter++"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer1->Add( m_buttonPMain, 0, wxALL, 5 );
m_staticText3 = new wxStaticText( this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText3->Wrap( -1 );
bSizer1->Add( m_staticText3, 0, wxALL, 5 );
this->SetSizer( bSizer1 );
this->Layout();
// Connect Events
m_buttonPMain->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PanelMAIN::m_btn_Counter_OnButtonClick ), NULL, this );
}
PanelMAIN::~PanelMAIN()
{
// Disconnect Events
m_buttonPMain->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PanelMAIN::m_btn_Counter_OnButtonClick ), NULL, this );
}
==== wxPanelAPP.h
#ifndef WXPANELAPP_H
#define WXPANELAPP_H
#include <wx/app.h>
class wxPanelApp : public wxApp
{
public:
virtual bool OnInit();
};
#endif // WXPANELAPP_H
==== wxPanelAPP.cpp
#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
#include "wxPanelApp.h"
#include "wxPanelMain.h"
IMPLEMENT_APP(wxPanelApp);
bool wxPanelApp::OnInit()
{
wxPanelFrame* frame = new wxPanelFrame(0L);
frame->SetIcon(wxICON(aaaa)); // To Set App Icon
frame->Show();
return true;
}
==== wxPanelMain.h
#ifndef WXPANELMAIN_H
#define WXPANELMAIN_H
#include "wxPanelApp.h"
#include "GUIFrame.h"
#include "MyPanel.h"
#include <iostream>
class wxPanelFrame: public GUIFrame
{
public:
wxPanelFrame(wxFrame *frame);
~wxPanelFrame();
wxPanel *m_wxpMain = new PanelMAIN(this, wxID_ANY);
private:
virtual void OnClose(wxCloseEvent& event);
virtual void OnQuit(wxCommandEvent& event);
void m_menuItemPanelMainOnMenuSelection( wxCommandEvent& event );
};
#endif // WXPANELMAIN_H
==== wxPanelMain.cpp
#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
#include "wxPanelMain.h"
wxPanelFrame::wxPanelFrame(wxFrame *frame) : GUIFrame(frame)
{
#if wxUSE_STATUSBAR
statusBar->SetStatusText(_("Simple Panel Test"), 0);
#endif
// Hide the panel
m_wxpMain->Show(false);
}
wxPanelFrame::~wxPanelFrame()
{
}
void wxPanelFrame::OnClose(wxCloseEvent &event)
{
Destroy();
}
void wxPanelFrame::OnQuit(wxCommandEvent &event)
{
Destroy();
}
void wxPanelFrame::m_menuItemPanelMainOnMenuSelection( wxCommandEvent& event )
{
// Show the panel
m_wxpMain->Show(true);
}
==== MyPanel.h
#ifndef MYPANEL_H
#define MYPANEL_H
#include "GUIFrame.h"
#include <iostream>
class MyPanel : public PanelMAIN
{
public:
MyPanel(wxPanel *panel);
virtual ~MyPanel();
int i{0};
protected:
private:
void m_btn_Counter_OnButtonClick( wxCommandEvent& event );
};
#endif // MYPANEL_H
==== MyPanel.cpp
#include "MyPanel.h"
MyPanel::MyPanel(wxPanel *panel) : PanelMAIN(panel)
{
std::cout << "MyPanel::MyPanel /*CONSTRUCTOR*/\n";
}
MyPanel::~MyPanel()
{
std::cout << "MyPanel::~MyPanel /*DESTRUCTOR*/\n";
}
void MyPanel::m_btn_Counter_OnButtonClick( wxCommandEvent& event )
{
wxString wxs_Count{};
i++;
wxs_Count << i;
m_staticText3->SetLabelText(wxs_Count);
}
You define your event handler in your derived class MyPanel, but you never create and instance of it. The line
wxPanel *m_wxpMain = new PanelMAIN(this, wxID_ANY);
only creates on object of the base class.
You should change this to
MyPanel *m_wxpMain = new MyPanel(this);
You also have an problem with the constructor for MyPanel. The parent needs to be a wxWindow not wxPanel. So the declaration should be something like
MyPanel(wxWindow *panel);
and the body should look something like
MyPanel::MyPanel(wxWindow *panel) : PanelMAIN(panel)
{
std::cout << "MyPanel::MyPanel /*CONSTRUCTOR*/\n";
}
I'm trying to create a simple frame in Qt with a tick and some text. I made two new label implementations because I wanted the labels to dynamically fill all the available space but when I resize the window the sizes are off, as shown by the qDebug output, which represents the size of the image label:
Resized: 244 , 244 <-- Window first created
Resized: 305 , 305 <-- Window maximized
Resized: 135 , 135 <-- Window restored to original size
As you can see, when the window is restored to its original size the image is not. The last size should be 244, 244.
The code which describes the behaviour of the two widgets is the following:
"widgets.h":
/*
* This file includes many custom widgets.
*/
#ifndef APOCRYPHA_WIDGETS
#define APOCRYPHA_WIDGETS
#include <QWidget>
#include <QLabel>
#include <QTimer>
#include <QPixmap>
#include <QResizeEvent>
#include <QPaintEvent>
class AutoTextLabel : public QLabel {
Q_OBJECT
public:
explicit AutoTextLabel(QWidget* parent);
AutoTextLabel(QWidget* parent, QString text);
protected:
void resizeEvent(QResizeEvent* event) override;
private:
QTimer* resizeTimer;
private slots:
void onResizeEnd();
};
class AutoImageLabel : public QLabel {
Q_OBJECT
public:
explicit AutoImageLabel(QWidget* parent);
AutoImageLabel(QWidget* parent, const QPixmap& pixmap);
void setFillOrientation(int orientation);
QSize sizeHint() const override;
public slots:
void setPixmap(const QPixmap &newPix);
void resizeEvent(QResizeEvent* event) override;
protected:
// void paintEvent(QPaintEvent* event) override;
private:
int fillOrientation;
int widthForHeight(int h) const;
int heightForWidth(int w) const override;
QPixmap scaledPixmap() const;
QPixmap labelPixmap;
};
#endif //APOCRYPHA_WIDGETS
"widgets.cpp":
/*
* This file includes many custom widgets.
*/
#include "widgets.h"
#include <QPainter>
#include <QDebug>
AutoTextLabel::AutoTextLabel(QWidget *parent, QString text) : QLabel(text, parent){
// Enable antialiasing
QFont aaFont(font());
aaFont.setStyleStrategy(QFont::PreferAntialias);
setFont(aaFont);
// This timer is used to fire a slot when a window is resized
resizeTimer = new QTimer();
resizeTimer->setSingleShot(true);
connect(resizeTimer, SIGNAL(timeout()), SLOT(onResizeEnd()));
}
AutoTextLabel::AutoTextLabel(QWidget *parent) : AutoTextLabel(parent, "") {}
void AutoTextLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
// Only fire when 25ms have passed since the last resize.
resizeTimer->start(25);
}
void AutoTextLabel::onResizeEnd() {
QFont updatedFont(font());
// Resize Text
if (!text().isEmpty()){
int fontSize = 1;
updatedFont.setPixelSize(fontSize);
QRect boundingRectangle;
// Update bounding rectangle
if (wordWrap())
boundingRectangle = QFontMetrics(updatedFont).boundingRect(contentsRect(), Qt::TextWordWrap, text());
else
boundingRectangle = QFontMetrics(updatedFont).boundingRect(text());
while (boundingRectangle.height() <= contentsRect().height()) {
fontSize++;
updatedFont.setPixelSize(fontSize);
// Update bounding rectangle
if (wordWrap())
boundingRectangle = QFontMetrics(updatedFont).boundingRect(contentsRect(), Qt::TextWordWrap, text());
else
boundingRectangle = QFontMetrics(updatedFont).boundingRect(text());
}
updatedFont.setPixelSize(fontSize - 1);
setFont(updatedFont);
}
}
/* Auto Image Label */
AutoImageLabel::AutoImageLabel(QWidget *parent, const QPixmap &pixmap) : QLabel(parent) {
setMinimumSize(1, 1);
setScaledContents(false);
setPixmap(pixmap);
}
AutoImageLabel::AutoImageLabel(QWidget *parent) : QLabel(parent) {
setScaledContents(false);
}
void AutoImageLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
if(!labelPixmap.isNull())
QLabel::setPixmap(scaledPixmap());
qDebug() << "Resized: " << scaledPixmap().width() << ", " << scaledPixmap().height();
}
int AutoImageLabel::widthForHeight(int h) const {
return labelPixmap.isNull() ? width() : (labelPixmap.width() * h) / labelPixmap.height();
}
int AutoImageLabel::heightForWidth(int w) const {
return labelPixmap.isNull() ? height() : (labelPixmap.height() * w) / labelPixmap.width();
}
void AutoImageLabel::setFillOrientation(int orientation) {
this->fillOrientation = orientation;
}
QSize AutoImageLabel::sizeHint() const {
if (fillOrientation == Qt::Horizontal)
return QSize(width(), heightForWidth(width()));
else
return QSize(widthForHeight(height()), height());
}
QPixmap AutoImageLabel::scaledPixmap() const {
return labelPixmap.scaled(sizeHint(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
void AutoImageLabel::setPixmap(const QPixmap &newPix) {
labelPixmap = newPix;
QLabel::setPixmap(scaledPixmap());
}
"other_frames.h":
//
// Created by Riccardo on 18/09/2017.
//
#ifndef APOCRYPHA_OTHER_FRAMES_H
#define APOCRYPHA_OTHER_FRAMES_H
#include <QFrame>
#include <QLabel>
#include <QGridLayout>
#include <QWidget>
#include <QResizeEvent>
#include <QPixmap>
#include <QTimer>
#include "widgets.h"
class ConfirmationFrame : public QFrame {
Q_OBJECT
public:
explicit ConfirmationFrame(QWidget* parent);
ConfirmationFrame(QWidget* parent, const QString& text);
private:
QGridLayout* layout;
AutoImageLabel* imageLabel;
AutoTextLabel* textLabel;
};
#endif //APOCRYPHA_OTHER_FRAMES_H
"other_frames.cpp":
//
// Created by Riccardo on 18/09/2017.
//
#include "other_frames.h"
#include <QDebug>
ConfirmationFrame::ConfirmationFrame(QWidget* parent, const QString &text) : QFrame(parent) {
textLabel = new AutoTextLabel(this, text);
QPixmap pix(":/images/check-tick.png");
imageLabel = new AutoImageLabel(this, pix);
textLabel->setAlignment(Qt::AlignCenter);
imageLabel->setAlignment(Qt::AlignCenter);
textLabel->setWordWrap(true);
// Green Background
setStyleSheet("background-color: rgba(106, 242, 94, 1);");
layout = new QGridLayout();
layout->setSpacing(0);
layout->setContentsMargins(32, 32, 32, 32);
layout->setRowStretch(0, 1);
layout->setRowStretch(1, 1);
layout->addWidget(imageLabel, 0, 1);
layout->addWidget(textLabel, 1, 1);
setLayout(layout);
}
ConfirmationFrame::ConfirmationFrame(QWidget *parent) : ConfirmationFrame(parent, "") {
}
"window_main.h":
#ifndef WINDOW_MAIN_H
#define WINDOW_MAIN_H
#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QGridLayout>
#include <QFrame>
#include <QScreen>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
QFrame *mainFrame;
void center(QScreen* screen);
void autoSetSize(QScreen* screen);
private:
void createMenu();
// Components
QGridLayout *mainLayout;
QMenuBar *menuBar;
QMenu *fileMenu;
};
#endif // WINDOW_MAIN
"window_main.cpp":
#include "window_main.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
mainFrame = new QFrame();
mainLayout = new QGridLayout();
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
createMenu();
mainFrame->setStyleSheet("background-color: red;");
mainFrame->setLayout(mainLayout);
setCentralWidget(mainFrame);
}
void MainWindow::createMenu(){
menuBar = new QMenuBar;
fileMenu = new QMenu(tr("&File"), this);
menuBar->addMenu(fileMenu);
setMenuBar(menuBar);
}
void MainWindow::center(QScreen *screen) {
QSize size = screen->availableSize();
int x = size.width() / 2 - width() / 2;
int y = size.height() / 2 - height() / 2;
move(x, y);
}
void MainWindow::autoSetSize(QScreen *screen) {
QSize screenSize = screen->availableSize();
// TODO Math.round
setMinimumSize(QSize((int)(screenSize.width() / 1.25), (int)(screenSize.height() / 1.25)));
}
"main.cpp":
#include <QApplication>
#include <iostream>
#include <QFile>
#include "quiz/choice.h"
#include "quiz/question.h"
#include "quiz/quizmaker.h"
#include <QSettings>
#include <QStandardPaths>
#include <QDebug>
#include <src/user_interface/other_frames.h>
#include "user_interface/window_main.h"
#include <QScreen>
#include <QFontDatabase>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
// Set Application Parameters
QCoreApplication::setOrganizationName("Riccardo Fagiolo");
QCoreApplication::setOrganizationDomain("kopharex.me");
QCoreApplication::setApplicationName("Apocrypha");
// Set application font
const int id = QFontDatabase::addApplicationFont(":/fonts/montserrat/Montserrat-Regular.otf");
QString family = QFontDatabase::applicationFontFamilies(id).at(0);
QFont font(family);
font.setStyleStrategy(QFont::PreferAntialias);
a.setFont(font);
// App Settings
QSettings settings;
settings.setValue("data_dir", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
// Create UI
auto* window = new MainWindow();
ConfirmationFrame* cframe = new ConfirmationFrame(window, "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?");
window->mainFrame->layout()->addWidget(cframe);
window->autoSetSize(a.primaryScreen());
//cframe->updateTextLabel();
window->show();
window->center(a.primaryScreen());
// [...] - Nothing related to user interface.
return a.exec();
}
Here is a screenshot of the current MainWindow and ConfirmationFrame to give you an idea of what i'm trying to accomplish:
Window Screenshot
All comments regarding the code are welcome.
Thanks for any help,
Riccardo
Hello I tried to fix the resizing issue with an hack.
Before starting the timer to resize the text, just reduce its font to a 1 pixel font:
void AutoTextLabel::resizeEvent(QResizeEvent *event) {
QWidget::resizeEvent(event);
// set a very small font, then start the timer
QFont updatedFont(font());
updatedFont.setPixelSize(1);
setFont(updatedFont);
// Only fire when 25ms have passed since the last resize.
resizeTimer->start(25);
}
Can the effect be acceptable in your opinion?
This code displays a single textbox and a button. When the user clicks the button, the window exits, however I want to put the textControl to the center of the window but it's not working. Here's my code:
// base.h
#ifndef base_h_
#define base_h_
#include <wx/app.h>
#include <wx/button.h>
#include <wx/string.h>
#include <wx/frame.h>
#include <wx/gdicmn.h>
#include <wx/sizer.h>
#include <wx/panel.h>
class MainApp : public wxApp {
public:
virtual bool OnInit();
};
class MainFrame: public wxFrame {
public:
MainFrame( const
wxString& title, const wxPoint& pos, const wxSize& size );
wxBoxSizer *sizer;
void OnExit(wxCommandEvent& event);
DECLARE_EVENT_TABLE()
};
#endif
// base.cpp
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "base.h"
IMPLEMENT_APP(MainApp)
bool MainApp::OnInit() {
MainFrame *MainWin = new MainFrame(_T("gui"), wxDefaultPosition, wxSize(5000, 5000));
MainWin->Show(TRUE);
SetTopWindow(MainWin);
return TRUE;
}
BEGIN_EVENT_TABLE ( MainFrame, wxFrame)
EVT_BUTTON ( 3, MainFrame::OnExit )
END_EVENT_TABLE()
MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size): wxFrame((wxFrame*)NULL,- 1, title, pos, size) {
wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
wxPanel *panel = new wxPanel(this, wxID_ANY, wxPoint(0, 0));
sizer->Add(new wxTextCtrl(panel , 1, ""), wxSizerFlags().Center());
sizer->SetSizeHints(this);
SetSizer(sizer);
}
void MainFrame::OnExit( wxCommandEvent& event) {
Close(TRUE);
}
I don't know what I'm doing wrong here, shouldn't wxSizerFlags().Center do exactly what I want?
Your text control is wrapped inside a wxPanel. You add the text control to the sizer and set the sizer to the frame. This won't work and may even cause errors. You need to create two sizers, one for the panel and one for the frame. You have several options: You can have the panel expand to the size of the frame and have the text ctrl placed in the center of the panel, or you can center the panel and have the text ctrl expand to the size of the panel. Here's some code for the first option:
wxPanel* panel = new wxPanel(this, wxID_ANY);
wxTextCtrl* text = new wxTextCtrl(panel, 1, "");
wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL);
panelSizer->Add(text, wxSizerFlags().Center());
panel->SetSizer(panelSizer);
wxBoxSizer* frameSizer = new wxBoxSizer(wxVERTICAL);
frameSizer->Add(panel, wxSizerFlags().Expand());
SetSizer(frameSizer);
Note that I'm not familiar with wxSizerFlags, but I suppose that it should work like this. You may also have to set a size for the panel explicitly - right now it will use some default size.