Reputation: 1
I want to implement object selection by allowing users to create a rectangular area using the mouse.
I'm creating a panel TPanel
that inherits from wxWindow
to handle certain events and perform redrawing.
Then I add a wxWrapSizer* imageWrapper
to it, into which I add ImageContainer
elements in std::vector<ImageContainer*> imageContent
from std::vector<wxImage> images
MyFrame.cpp:
TPanel leftPanel = new TPanel(menuSplitter, &cManager, wxID_ANY, wxDefaultPosition, wxSize(600, 494));
wxWrapSizer imageWrapper = new wxWrapSizer(wxHORIZONTAL);
leftPanel->SetSizer(imageWrapper);
for (auto& img : images) {
auto image = new ImageContainer(leftPanel, &img, &cManager, wxID_ANY, wxDefaultPosition, wxSize(120, 100));
imageContent.push_back(image);
imageWrapper->Add(image, 0, wxALL, FromDIP(10));
}
So I track the area of selection I need TPanel.h / TPanel.cpp:
class TPanel : public wxScrolled<wxWindow> {
public:
TPanel(wxWindow* parent, ColorManager* clrM, wxWindowID winid = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxNO_BORDER, const wxString& name = wxASCII_STR(wxPanelNameStr));
private:
wxPoint startSel, endSel;
ColorManager* colorManager;
bool isSelect = false;
// ... and other minor details
};
void TPanel::OnMouseLeftDown(wxMouseEvent& evt) {
if (!isSelect) {
CaptureMouse();
isSelect = true;
startSel = ScreenToClient(wxGetMousePosition());
}
}
void TPanel::OnMouseLeftUp(wxMouseEvent& evt) {
if (isSelect) {
ReleaseMouse();
isSelect = false;
Refresh();
}
}
void TPanel::OnMouseMove(wxMouseEvent& evt) {
if (isSelect) {
endSel = ScreenToClient(wxGetMousePosition());
Refresh();
}
}
void TPanel::OnMouseLost(wxMouseCaptureLostEvent& evt) {
ReleaseMouse();
isSelect = false;
Refresh();
}
void TPanel::OnSize(wxSizeEvent& event) {
wxSize size = GetClientSize();
this->SetVirtualSize(size);
event.Skip();
}
Ok, I can draw this area directly on the panel, but then it will be displayed under the elements of imageContent
. What I want is to display it above all child windows of the panel, within its bounds.
wxWindow
in the constructor of TPanel
to create a transparent window above and draw the selection on it. The window was indeed created above the child elements, but wxBG_STYLE_TRANSPARENT
didn't provide any transparency.wxOverlay
for me to understand how to use it properly. Among methods like wxClientDC
, wxWindowDC
, wxScreenDC
, I managed to achieve flickering drawing only with wxScreenDC
. In other cases, I couldn't get the area to display at all.upd.
For now I have chosen a workaround. The TPanel
generates a selection start event, which MyFrame
handles in MultiSelection()
. Here, the intersection of the rectangular stroke area with the wxRect
of control is checked and the area that needs to be painted over the child element is passed. The method works, but I'm not sure it works the same way in large commercial programs or operating systems.
void MyFrame::MultiSelection(wxCommandEvent& evt) {
wxRect selectRC = wxRect(leftPanel->strSel, leftPanel->endSel);
for (auto& item : imageContent) {
if (item->GetRect().Intersects(selectRC)) {
item->isMark = true;
item->isSelect = true;
item->selectRC = wxRect(selectRC.GetX() - item->GetPosition().x, selectRC.GetY() - item->GetPosition().y,
selectRC.GetWidth(), selectRC.GetHeight());
}
else {
item->isMark = false;
item->isSelect = false;
}
}
}
Upvotes: 0
Views: 81