i just started to learn wxWidgets and I'm trying to create some kind of Image Opener.
But i cant understand how to add an image...
i seen some stuff about wxImage, wxBitMap,wxStaticBitmap, but i couldn't understand any of them or the difference between them.
#include <wx/wx.h>
#include <wx/filedlg.h>
#include <wx/wfstream.h>
class MyApp : public wxApp
{
public:
virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
MyFrame (const wxString& event);
void OnOpen(wxCommandEvent& event);
void OnQuit(wxCommandEvent& event);
private:
DECLARE_EVENT_TABLE();
};
DECLARE_APP(MyApp);
IMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
MyFrame *frame = new MyFrame(wxT("Minimal wxWidgets App"));
frame->Show(true);
return true;
}
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(wxID_OPEN, MyFrame::OnOpen)
EVT_MENU(wxID_EXIT, MyFrame::OnQuit)
END_EVENT_TABLE()
void MyFrame::OnOpen(wxCommandEvent& event)
{
wxFileDialog openFileDialog(this, ("Open JPEG file"), "", "", "JPEG files (*.jpg)|*jpg", wxFD_OPEN|wxFD_FILE_MUST_EXIST);
if(openFileDialog.ShowModal() == wxID_CANCEL)
return;
wxFileInputStream input_stream(openFileDialog.GetPath());
if(!input_stream.IsOk())
{
wxLogError("Cannot Open File '%s'.", openFileDialog.GetPath());
return;
}
}
void MyFrame::OnQuit(wxCommandEvent& event)
{
Close(true);
}
MyFrame::MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title)
{
wxMenuBar * menuBar = new wxMenuBar;
wxMenu * exitMenu = new wxMenu;
wxMenu * openMenu = new wxMenu;
exitMenu->Append(wxID_EXIT);
openMenu->Append(wxID_OPEN);
menuBar->Append(openMenu, "&Open");
menuBar->Append(exitMenu, "&Exit");
SetMenuBar(menuBar);
CreateStatusBar(2);
SetStatusText(wxT("Image Opener !"));
}
can someone show an example of adding an image on wxwidgets ? or adding it to my code .
thanks for help !
wxImage is a portable representation of an image, wxBitmap is a platform-specific but more efficient equivalent. Generally speaking, wxImage is convenient for working with image data, but it needs to be converted to wxBitmap to be displayed.
Both of these classes are just abstract images, while wxStaticBitmap is a control showing an image, i.e. something you can really see on screen.
The image sample (under samples directory of your wxWidgets distribution) shows how to use the different classes and draw images directly.
wxImage and wxBitmap are almost same and conversion between them is easy. wxStaticBitmap is used to display a wxBitmap.it can be done by following example(StaticBitmap1 is your wxStaticBitmap and btmp is your wxBitmap):
StaticBitmap1->SetBitmap(btmp);
Related
I made a GUI application in wxWidgets and kept receiving anti virus alerts by various users. I spent a great amount of time commenting out code and re-uploading the EXE to VirusTotal. It turns out, none of this was my code. Using the wxWidgets framework alone will cause plenty of detections. I tried again by compiling a simple hello world application and sure enough, this is the result:
Full source code:
// wxWidgets "Hello world" Program
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
// Required for static linking
#pragma comment(lib, "comctl32")
#pragma comment(lib, "Rpcrt4")
class MyApp : public wxApp
{
public:
virtual bool OnInit();
};
class MyFrame : public wxFrame
{
public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
private:
void OnHello(wxCommandEvent& event);
void OnExit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
wxDECLARE_EVENT_TABLE();
};
enum
{
ID_Hello = 1
};
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(ID_Hello, MyFrame::OnHello)
EVT_MENU(wxID_EXIT, MyFrame::OnExit)
EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit()
{
MyFrame* frame = new MyFrame("Hello World", wxPoint(50, 50), wxSize(450, 340));
frame->Show(true);
return true;
}
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame(NULL, wxID_ANY, title, pos, size)
{
wxMenu* menuFile = new wxMenu;
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
"Help string shown in status bar for this menu item");
menuFile->AppendSeparator();
menuFile->Append(wxID_EXIT);
wxMenu* menuHelp = new wxMenu;
menuHelp->Append(wxID_ABOUT);
wxMenuBar* menuBar = new wxMenuBar;
menuBar->Append(menuFile, "&File");
menuBar->Append(menuHelp, "&Help");
SetMenuBar(menuBar);
CreateStatusBar();
SetStatusText("Welcome to wxWidgets!");
}
void MyFrame::OnExit(wxCommandEvent& event)
{
Close(true);
}
void MyFrame::OnAbout(wxCommandEvent& event)
{
wxMessageBox("This is a wxWidgets' Hello world sample",
"About Hello World", wxOK | wxICON_INFORMATION);
}
void MyFrame::OnHello(wxCommandEvent& event)
{
wxLogMessage("Hello world from wxWidgets!");
}
How can these be fixed without contacting each AV vendor? Clearly, the code is not malicious and wxWidgets is a popular cross-platform GUI framework which shouldn't cause any AV detections on its own. The static EXE however is quite big and pulls in a lot of Windows API functions so it's hard to even pinpoint anything.
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 use wxWidget-3.1.4 under windows 10
I try to process mouse events from my class.
Header class:
#include "wx/wxprec.h"
#include <wx/wfstream.h>
class MainWindow : public wxFrame
{
public:
MainWindow(const wxString& title);
void OnQuit(wxCommandEvent& event);
void OnOpenImage(wxCommandEvent& WXUNUSED);
void OnEditImage(wxCommandEvent& WXUNUSED);
//will redirect mouse event to class ImageDrawing
void OnMouseWheel(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event);
void OnMouseDown(wxMouseEvent& event);
void OnMouseUp(wxMouseEvent& event);
private:
//wx Panel for drawing image
wxPanel* m_background;
wxImage* m_Image;
...
};
Cpp file:
MainWindow::MainWindow(const wxString& title): wxFrame(NULL, wxID_ANY, title)
{
m_background = new wxPanel(this, wxID_ANY);
m_background->Bind(wxEVT_PAINT, &MainWindow::OnPaint, this);
}
void MainWindow::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(true);
}
void MainWindow::OnOpenImage(wxCommandEvent& WXUNUSED(event))
{
wxString file = OpenFileDialog("Open Image file", "png files (*.png)|*.png");
openImage(file, true);
}
void MainWindow::OnEditImage(wxCommandEvent& WXUNUSED(event))
{
wxString file = OpenFileDialog("Open Image file", "png files (*.png)|*.png");
// some logic
}
void MainWindow::OnMouseWheel(wxMouseEvent& event)
{
std::cout<<"OnMouseWheel(event)";
}
void MainWindow::OnMouseMove(wxMouseEvent& event)
{
std::cout<<"OnMouseMove(event)";
}
void MainWindow::OnMouseDown(wxMouseEvent& event)
{
std::cout<<"OnMouseDown(event)";
}
void MainWindow::OnMouseUp(wxMouseEvent& event)
{
std::cout<<"OnMouseUp(event)";
}
wxBEGIN_EVENT_TABLE(MainWindow, wxFrame)
EVT_MENU(Minimal_Quit, MainWindow::OnQuit)
EVT_MENU(Open_Image, MainWindow::OnOpenImage)
EVT_MENU(Edit_Image, MainWindow::OnEditImage)
EVT_MOTION(MainWindow::OnMouseMove)
EVT_MOUSEWHEEL(MainWindow::OnMouseWheel)
EVT_LEFT_DOWN(MainWindow::OnMouseDown)
EVT_LEFT_UP(MainWindow::OnMouseUp)
EVT_RIGHT_DOWN(MainWindow::OnMouseDown)
EVT_RIGHT_UP(MainWindow::OnMouseUp)
wxEND_EVENT_TABLE()
the problem is that event menu works fine, also OnMouseWheel works, but all other mouse events are not working. Googling problem shows that a reason for this is because a parent component, in my case wxFrame is included some child, like wxPanel, and this child component could intercept events.
So why OnMouseWheel is working and all other is not. the same behaviour if I change wxFrame to wxPanel in event table and if I didn't use m_background.
I was able to solve this problem by applying the following changes in constructor:
MainWindow::MainWindow(const wxString& title): wxFrame(NULL, wxID_ANY, title)
{
m_background = new wxPanel(this, wxID_ANY);
m_background->Bind(wxEVT_PAINT, &MainWindow::OnPaint, this);
m_background->Connect(wxEVT_MOTION, wxMouseEventHandler(MainWindow::OnMouseMove));
m_background->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MainWindow::OnMouseDown));
m_background->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(MainWindow::OnMouseUp));
}
in each function that if you want to access to some class member or parameter you need to do the following:
void MainWindow::OnMouseMove(wxMouseEvent& event)
{
MainWindow* pointer = dynamic_cast<MainWindow*>(this->GetParent());
if(pointer->m_path.size() > 0)
pointer->m_drawing->OnMove(event);
}
and instead of this, you need to use a pointer, the reason for this because this now point to m_background.
Last step is to delete this function from wx_EVENT_TABLE
I am trying to learn WxWidgets with C++ (I am very new at this), and I have created a window with a black background color and has a big red "X" on it. I have to edit the code so that the "X" changes its size with the window as I am resizing the window. How can I properly implement the resize event handler to this code?
Here's a screenshot of what my code produces: https://imgur.com/a/0I8EG5y
Here's what I have so far"
#include <wx/wx.h>
#include <wx/dcbuffer.h>
class MyCanvas : public wxWindow
{
public:
MyCanvas(wxWindow* parent)
: wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
{
SetBackgroundStyle(wxBG_STYLE_PAINT);
Bind(wxEVT_PAINT, &MyCanvas::OnPaint, this);
}
private:
void OnPaint(wxPaintEvent&)
{
wxAutoBufferedPaintDC dc(this);
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxBLACK_BRUSH);
dc.DrawLine(0,0,485,485);
dc.DrawLine(0, 485, 485, 0);
}
};
class MyFrame : public wxFrame
{
public:
MyFrame()
: wxFrame(NULL, wxID_ANY, _("Resizable X"), wxDefaultPosition, wxSize(500, 525))
{
wxBoxSizer* bSizer = new wxBoxSizer(wxVERTICAL);
bSizer->Add(new MyCanvas(this), 1, wxEXPAND);
SetSizer(bSizer);
}
};
/**** MyApp ****/
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
MyFrame* frame = new MyFrame();
frame->Show();
return true;
}
};
IMPLEMENT_APP(MyApp)
The simplest way to implement your resize handler is to do the following in MyCanvas ctor:
Bind(wxEVT_SIZE, [this](wxSizeEvent& event) { Refresh(); event.Skip(); });
This will fully refresh your canvas every time it is resized, i.e. will generate a wxEVT_PAINT that will result in a call to your existing OnPaint() handler.
Of course, for this to be actually useful, your OnPaint() should take the current window size into account, i.e. use GetClientSize() instead of hardcoded 485.
I want to view an image in one of wxSplitterWindow using wxScrolledWindow.
I derived class from wxPanel, which I add into wxScrolledWindow. But the result is not what i want.(
class ImagePanel : public wxPanel
{
public:
//ImagePanel(wxFrame* parent);
ImagePanel(wxWindow* parent);
void paintEvent(wxPaintEvent& event);
void paintNow();
void setBitmap(wxBitmap& imBitmap);
void setBitmap(wxImage& img);
int GetHeight();
int GetWidth();
void render(wxDC& dc);
DECLARE_EVENT_TABLE()
private:
wxBitmap curBitmap;
};
Paint event:
void ImagePanel::paintEvent(wxPaintEvent& event)
{
wxBufferedPaintDC dc(this);
render(dc);
}
This is how I have written the interface into main frame constructor:
topSizer = new wxBoxSizer(wxVERTICAL);
topSplitter = new wxSplitterWindow(this,ID_TOPSPLITTER,wxDefaultPosition,wxDefaultSize,wxSP_LIVE_UPDATE|wxSP_3D);
topSizer->Add(topSplitter,1,wxALL|wxEXPAND,0);
imagePanel = new wxPanel(topSplitter,ID_IMAGEPANEL);
imageSizer = new wxBoxSizer(wxVERTICAL);
imagePanel->SetSizer(imageSizer);
optionPanel = new wxPanel(topSplitter,ID_OPTIONPANEL);
optionSizer = new wxBoxSizer(wxVERTICAL);
optionPanel->SetSizer(optionSizer);
topSplitter->SplitVertically(imagePanel, optionPanel);
topSplitter->SetMinimumPaneSize(200);
//===========================================
//image panel interface
imageScWindow=new wxScrolledWindow(imagePanel,ID_IMAGESCWINDOW,wxDefaultPosition,wxDefaultSize,
wxVSCROLL|wxHSCROLL|wxALL|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE);
imgArea = new ImagePanel(imageScWindow);
imageSizer->Add(imageScWindow,1,wxEXPAND,0);
scrollSizer = new wxBoxSizer(wxVERTICAL);
imageScWindow->SetSizer(scrollSizer);
scrollSizer->Add(imgArea,1,wxEXPAND,0);
imageScWindow->SetTargetWindow(imgArea);
And this is the function that loads image:
void MainFrame::Setpic(wxCommandEvent& event)
{
wxString path = GetCurrentWorkingDir()+wxT("\\")+tmptxt1->GetValue();
wxImage img(path);
wxBitmap imBitmap(img,-1);
imgArea->setBitmap(imBitmap);
imageScWindow->SetScrollbars(1,1,imgArea->GetWidth(),imgArea->GetHeight());
imageScWindow->Refresh();
}
Thats what i get:
https://i.imgur.com/x1GIlrl.png
I have also tried to do like this in the constructor, without SetTargetArea:
//===========================================
//image panel interface
imageScWindow=new wxScrolledWindow(imagePanel,ID_IMAGESCWINDOW,wxDefaultPosition,wxDefaultSize,
wxVSCROLL|wxHSCROLL|wxALL|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE);
imgArea = new ImagePanel(imageScWindow);
imageSizer->Add(imageScWindow,1,wxEXPAND,0);
scrollSizer = new wxBoxSizer(wxVERTICAL);
imageScWindow->SetSizer(scrollSizer);
scrollSizer->Add(imgArea,1,wxEXPAND,0);
Then image shows properly, but if I change the frame size or move splitter, scrollbars disappear, and I have to set them again somwhere.
Then i tried to do like this:
int prvx,prvy;
void ImagePanel::paintEvent(wxPaintEvent& event)
{
reinterpret_cast<wxScrolledWindow*>(this->GetParent())->GetViewStart(&prvx,&prvy);
reinterpret_cast<wxScrolledWindow*>(this->GetParent())->SetScrollbars(1,1,curBitmap.GetWidth(),curBitmap.GetHeight());
reinterpret_cast<wxScrolledWindow*>(this->GetParent())->Scroll(wxPoint(prvx,prvy));
wxBufferedPaintDC dc(this);
render(dc);
}
It shows properly, but lags while scrolling, even without wxFULL_REPAINT_ON_RESIZE in wxScrolledWindow. The reason why it is in paint event: if I add this into OnSize event, program crashes. What to do?
I'm not sure where to begin answering your question. Here's a minimal sample of a frame that has a splitter with a bitmap on the left and a panel on the right. I hope you can adapt this sample to do what you need.
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include <wx/scrolwin.h>
#include <wx/splitter.h>
#include <wx/dcbuffer.h>
class MyFrame : public wxFrame
{
public:
MyFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo",
wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize,
int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
private:
void OnScrollPaint( wxPaintEvent& event );
wxScrolledCanvas* m_canvas;
wxBitmap m_bitmap;
};
MyFrame::MyFrame( wxWindow* parent, int id, wxString title, wxPoint pos,
wxSize size, int style )
:wxFrame( parent, id, title, pos, size, style )
{
m_bitmap=wxBitmap ("test.png", wxBITMAP_TYPE_PNG );
wxSplitterWindow* m_splitter1
= new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSP_LIVE_UPDATE );
m_canvas = new wxScrolledCanvas( m_splitter1, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSTATIC_BORDER|wxHSCROLL|wxVSCROLL );
m_canvas->SetScrollRate( 5, 5 );
m_canvas->SetVirtualSize(m_bitmap.GetWidth(), m_bitmap.GetHeight());
m_canvas->SetBackgroundStyle(wxBG_STYLE_PAINT);
m_canvas->Bind( wxEVT_PAINT, &MyFrame::OnScrollPaint , this );
wxPanel* m_panel2 = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSTATIC_BORDER|wxTAB_TRAVERSAL );
m_splitter1->SplitVertically( m_canvas, m_panel2, GetSize().x/2 );
}
void MyFrame::OnScrollPaint( wxPaintEvent& event )
{
wxAutoBufferedPaintDC dc(m_canvas);
m_canvas->DoPrepareDC(dc);
dc.Clear();
dc.DrawBitmap(m_bitmap,0,0);
}
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
wxInitAllImageHandlers();
MyFrame* frame = new MyFrame(NULL);
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
To run this, be sure to change "test.png" in line 35 to the name of an actual image file on your computer (and change wxBITMAP_TYPE_PNG if the image file isn't a png).
The important parts are:
Set the background style of the canvas to wxBG_STYLE_PAINT as shown in line 46.
In the paint handler, call the DoPrepareDC method on the paintdc.
By the way, the paint handler shown in my sample isn't very good. It draws the entire bitmap every time. A better approach would be to get the update region and only redraw the parts that are needed, but I wanted to keep this simple.