wxWidgets wxTextCtrl crash when deleting - c++

wxTextCtrl causes some memory allocation problem when tried to be deleted or it's value changed. Here's some code insight:
wxTextCtrl* s = new wxTextCtrl(...);
s->SetValue("abc");//crash
delete s//crash
It's like all of its members are const's. Here is what VisualStudio says when it crashes:
An unhandled exception of type 'System.AccessViolationException'
occurred in Unknown Module.
Additional information: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
And even when i try the wxWidgets default destroy:
parent->DestroyChildren(); //ofc the parent is wxPane passed in constructor of s
Any help will be appreciated.
Here's some actual code from the only functions calling wxTextCtrl:
void AddButton::OnAction(wxSize* frame){
if ( !DoAction ){
if ( ! thy )
{
thy = new wxPanel
(mParent, -1,
wxPoint(0, 0),
wxSize(PanelWidth, mParent->GetSize().GetHeight()),
wxBORDER_NONE | wxFRAME_FLOAT_ON_PARENT );
thy->SetBackgroundColour(wxColor(30,30,30));
thy->Show();
if ( ! AddPanelDialog ){
//AddPanelDialog = (new _Text
//(this, thy, "add link...", wxPoint(1, 30), wxSize(PanelWidth - 30, 20),
//wxBORDER_NONE | wxTE_PROCESS_ENTER ));
wxTextCtrl* s = new wxTextCtrl(thy, -1, "", wxPoint(1, 30), wxSize(PanelWidth - 30, 20),
wxBORDER_NONE | wxTE_PROCESS_ENTER );
s->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(_Text::OnEnter));
s->Show();
}
if ( !ConfirmPanel ){
ConfirmPanel = new wxPanel
(thy, -1, wxPoint(PanelWidth - 28, 30), wxSize(27, 20),
wxBORDER_NONE | wxFRAME_FLOAT_ON_PARENT );
ConfirmPanel->SetBackgroundColour(wxColor(38, 145, 232));
ConfirmPanel->Show();
}
}
else {
thy->Show();
}
gui* rmd = (gui*)mParent;
rmd->LeftPanelActivate();
rmd->SetNewPositions(rmd->GetParent()->GetSize());
Button::Update();
helper::SendRedrawEvent(mParent);
DoAction = true; // indicates action activated
}
else{
thy->Hide();
gui* rmd = (gui*)mParent;
rmd->LeftPanelActivate(false);
rmd->SetNewPositions(rmd->GetParent()->GetSize());
Button::Update();
helper::SendRedrawEvent(mParent);
DoAction = false; // indicates action activated
}
}
and function that calls SetValue()
void AddButton::OnEnter(wxCommandEvent& event)//enter button handler
{
wxTextCtrl* _t = (wxTextCtrl*)this;
_Clear();
*_t<<"sup";
}

I think you have a problem with understanding of Connect(). If you're using it to connect to a method of a different object, you must pass a pointer to this object as the last argument (called eventSink in the documentation). Your method is almost certainly being called on a wrong object pointer.
And you should absolutely never, ever have to cast this like you do in OnEnter().

Are you sure that you really need to delete the wxTextCtrl? If this text control is placed into sizer then sizer is responsible for it and will destroy it when needed. You probably need to detach the text control from sizer and then delete it.
Also you should use Destroy() method instead of delete operator. This is clearly explained in docs.
As for crash on SetValue() call: have you tried to use wxT("abc")? Also what version of wxWidgets, OS and compiler are you using? Haven't experienced such problems with wxWidgets at all. Maybe you could post some meaningful piece of code which can help to identify the problem?

Related

How can I cast Gtk::Widget to GtK::ScrolledWindow on gtkmm?

On the code bellow I am setting ScrolledWindows on a grid container and then setting their properties in a loop, because I want to put TextViews on the grid. I do not want to use TreeView because it will be ackward to put long or moderate texts there, which is what I am intending. Unfortunately the function get_child_at(int col,int row), for getting the attached widgets returns Gtk::Widget and for the properties I need I must do a cast for Gtk::ScrolledWindow; which I am not being able to do.
(some code)
descriptors->attach(* (new Gtk::ScrolledWindow ()), 0,0);
descriptors->attach(* (new Gtk::ScrolledWindow ()), 1,0);
descriptors->attach(* (new Gtk::ScrolledWindow ()), 2,0);
(some other code)
for(int i = 0; i < 3; i++)
{
//Glib::RefPtr<Gtk::ScrolledWindow> * disposable_pointer = new Glib::RefPtr<Gtk::ScrolledWindow>();
//disposable_pointer = descriptors->get_child_at (i,0);
//Glib::RefPtr<Gtk::ScrolledWindow> disposable_pointer = Glib::RefPtr<Gtk::Widget>::cast_dynamic(*descriptors->get_child_at (i,0));
//Glib::RefPtr<Gtk::ScrolledWindow>Glib::RefPtr<Gtk::ScrolledWindow>::cast_dynamic
//current_grid_child_scrolledWin = Glib::RefPtr<Gtk::ScrolledWindow>cast_dynamic(descriptors->get_child_at (i,0));
//current_grid_child_scrolledWin = disposable_pointer->get();
Glib::RefPtr<Gtk::Widget> * something = new Glib::RefPtr<Gtk::Widget>(descriptors->get_child_at (i,0));
Glib::RefPtr<Gtk::ScrolledWindow> disposable_pointer = *something;
current_grid_child_scrolledWin->set_vadjustment (Glib::RefPtr<Gtk::Adjustment>());
current_grid_child_scrolledWin->set_hadjustment (Glib::RefPtr<Gtk::Adjustment>());
current_grid_child_scrolledWin->set_policy (Gtk::PolicyType::POLICY_AUTOMATIC, Gtk::PolicyType::POLICY_AUTOMATIC);
current_grid_child_scrolledWin->set_vexpand (true);
current_grid_child_scrolledWin->set_hexpand (true);
current_grid_child_scrolledWin->set_margin_end (10);
current_grid_child_scrolledWin->set_margin_bottom (10);
current_grid_child_scrolledWin->set_visible (true);
}
the last error I got was
/usr/include/glibmm-2.4/glibmm/refptr.h:309:31: error: invalid conversion from 'Gtk::Widget*' to 'Gtk::ScrolledWindow*' [-fpermissive]
309 | pCppObject_(src.operator->())
| ^
| |
| Gtk::Widget*
I considered the gtkmm documentation on using casting with Glib::RefPtr
As we can see from the Gtk::Grid documentation, the return type of get_child_at is a raw pointer to a widget:
Widget* Gtk::Grid::get_child_at(int column,
int row
)
and not a smart pointer (in your case a Glib::Refptr). This is because the caller of get_child_at is not responsible to manage the lifetime of the object pointed to by the returned pointer. You simply get a handle, work on it and then leave it alone. Someone else is responsible to call delete on it. Here is how I would do it in your case:
#include <gtkmm.h>
#include <iostream>
int main(int argc, char *argv[])
{
// Initialize Gtkmm:
auto app = Gtk::Application::create(argc, argv, "so.question.q66162108");
// Create a grid and attach a scrolled window:
Gtk::Grid container;
Gtk::ScrolledWindow scrolledWindow;
// Add the scrolled window to the grid. Make sure the container is responsible
// of deleting it! Otherwise, remeber to call delete on it:
container.attach(*Gtk::manage(new Gtk::ScrolledWindow()), 0, 0, 1, 1);
// Here, you get a raw pointer to a widget:
Gtk::Widget* pWidget = container.get_child_at(0, 0);
// We cast it to its most derived type:
Gtk::ScrolledWindow* pScrolledWindow = dynamic_cast<Gtk::ScrolledWindow*>(pWidget);
// If the cast fail (i.e. not a ScrolledWindow at (0, 0), then the
// casted pointer will be set to nullptr:
if(pScrolledWindow)
{
std::cout << "Casting worked" << std::endl;
// Handle properties here...
pScrolledWindow->set_visible (true);
// Set other properties here...
}
return 0;
} // At this point the container is destroyed and since Gtk::manage
// was used, the scrolled window will be automatically deleted.
Notice that nowhere is this code I am using a smart pointer. This is because when I new my Gtk::ScrolledWindow, I use Gtk::manage*. This function marks the object (here the Gtk::ScrolledWindow) as owned by its parent container widget (Here the Gtk::Grid), so you don't need to delete it manually. I becomes the container's responsibility to call delete on its children when it goes away.
*If you use a newer Gtkmm version, you will have to use make_managed<T> instead. See here.

wxOwnerDrawnComboBox on OSX has an extra row at the bottom of the scroll

I've implemented a custom wxOwnerDrawnComboBox based on the API docs. I then placed it on a wxPanel then used SetPopupMaxHeight to limit the combo popup to show only 3 items at a time. But the popup shows an extra white row at the bottom of the popup window.
Here are screenshots (I implemented it on the minimal_cocoa sample project):
As shown, there are only 6 items but at the end of "item 5", there's an extra row.
Some notes on the issue:
It is always the default white (checked by customizing the bg of the
other rows to black)
It only happens when using SetPopupMaxHeight
It only happens on Mac (i.e. no issue on Windows)
Clicking on that extra row will close the popup (so I guess it's drawn part of the popup window)
Here is the code (simplified for the minimal_cocoa project):
// CUSTOM CLASS DECLARATION
class MyOwnerDrawnComboBox : public wxOwnerDrawnComboBox
{
public:
static int getItemHeight()
{
return 25;
}
public:
// ctor
MyOwnerDrawnComboBox(wxWindow* parent,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
int n = 0,
const wxString choices[] = NULL,
long style = wxODCB_STD_CONTROL_PAINT)
: wxOwnerDrawnComboBox(parent,
wxID_ANY,
wxEmptyString,
pos,
size,
n,
choices,
style,
wxDefaultValidator,
"MyOwnerDrawnComboBox")
{
}
// overrides
virtual void OnDrawItem (wxDC& dc, const wxRect& rect, int item, int flags) const
{
dc.SetTextForeground(*wxRED);
// for debugging purposes, display the item index instead
wxString label = wxString::Format("item %d", item);
dc.DrawLabel(label, rect, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
}
virtual wxCoord OnMeasureItem (size_t item) const
{
return 25;
}
virtual wxCoord OnMeasureItemWidth (size_t item) const
{
return -1; // use default
}
};
// CUSTOM CLASS USAGE
wxPanel* panel = new wxPanel(this, wxID_ANY);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
wxString items[] = {"1", "2", "3", "4", "5", "6"}; // unused
MyOwnerDrawnComboBox* odcb = new MyOwnerDrawnComboBox(panel,
wxDefaultPosition,
wxSize(150, 30),
6,
items);
odcb->SetPopupMaxHeight(3 * MyOwnerDrawnComboBox::getItemHeight());
sizer->Add(odcb, 0, wxALL, 10);
sizer->Layout();
panel->SetSizer(sizer);
I've tried a few things:
Used the default OnDrawItem method (same issue)
Checked for extra calls to OnDrawItem (no extra calls)
Adjusted the returned item height in OnMeasureHeight (same issue)
Checked the behavior on the samples/combo/combo.cpp sample (same issue)
Some info on my wxWidgets build:
Cloned it directly from their github repo
Made no changes to the wxWidgets source aside from defining wxUSE_XTEST 1 in setup.h
I checked and wxUSE_ODCOMBOBOX and wxUSE_COMBOCTRL are #define'd
Used the following options for ../configure
--with-osx_cocoa
--with-macosx-version-min=10.7
--with-macosx-sdk=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk
--enable-debug
--disable-shared
--enable-unicode
--prefix="$(pwd)"
Some info on my env:
macOS 10.12.5 (Sierra)
Xcode 8.3.3 (8E3004b)
minimal_cocoa displays wxWidgets 3.1.1
Has anyone encountered this issue before?
I'm working around it for now by not using SetPopupMaxHeight anymore.
If someone has a solution though, do share.
I fixed it by doing some changes to the wx source.
src/generic/vscroll.cpp
wxVarScrollHelperBase::DoScrollToUnit:
// determine the real first unit to scroll to: we shouldn't scroll beyond
// the end
size_t unitFirstLast = FindFirstVisibleFromLast(m_unitMax - 1, true);
if ( unit > unitFirstLast )
unit = unitFirstLast;
Pass false instead to FindFirstVisibleFromLast.
This will allow the method to consider an item as the first item even though the last item is only partially visible ("partially" here, based on my testing, is really like "almost fully visible", with only about ~2pts that are hidden). With true, the scroll moves down to the next item, thereby adding the extra row.
src/generic/odcombo.cpp
wxVListBoxComboPopup::OnMouseMove:
// Only change selection if item is fully visible
if ( (y + fromBottom) >= 0 )
{
wxVListBox::SetSelection((int)line);
return;
}
To match the 2pt borders being considered in wxVListBoxComboPopup::GetAdjustedSize, I changed the IF condition to (y + fromBottom + 2) to allow moving the mouse over the last item in the scrolled window, even though it isn't fully visible.
src/generic/vlbox.cpp
else // line is at least partly visible
{
// it is, indeed, only partly visible, so scroll it into view to
// make it entirely visible
// BUT scrolling down when m_current is first visible makes it
// completely hidden, so that is even worse
while ( (size_t)m_current + 1 == GetVisibleRowsEnd() &&
(size_t)m_current != GetVisibleRowsBegin() &&
ScrollToRow(GetVisibleBegin() + 1) ) ;
Comment-out that while-loop to disable auto-scrolling when the mouse pointer is over the partially visible item.

Crash while calling setItemWidget

I am using a QTreeWidget and setting a widget for the QTreeWidgetItem in the QTreeWidget. It is working fine but when I do the same for second time, the application is crashing.
The below is working fine.
QTreeWidget* treewidget = new QTreeWidget();
QTreeWidgetItem* item0 = new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item0")));
treewidget->insertTopLevelItem(0,item0);
QSlider* slider0 = new QSlider();
treewidget->setItemWidget(item0, 0, slider0);
But if I add the last line once again, it is crashing when running the application.
The below is crashing.
QTreeWidget* treewidget = new QTreeWidget();
QTreeWidgetItem* item0 = new QTreeWidgetItem((QTreeWidget*)0, QStringList(QString("item0")));
treewidget->insertTopLevelItem(0,item0);
QSlider* slider0 = new QSlider();
treewidget->setItemWidget(item0, 0, slider0);
treewidget->setItemWidget(item0, 0, slider0); // Intentionally added to simulate the issue
The above is an example to show the issue, but in my application, based on some events, I delete the tree widget items and add it later. When I set the item widget (after adding the items later), I am getting the crash.
I could not figure out why. Any ideas? FYI, I am using Qt 5.3.2 MSVC 2010, 32 bit.
treewidget->setItemWidget(item0, 0, slider0);
treewidget->setItemWidget(item0, 0, slider0);// Intentionally added to simulate the issue
I look at Qt code (4.x):
void QTreeWidget::setItemWidget(QTreeWidgetItem *item, int column, QWidget *widget)
{
Q_D(QTreeWidget);
QAbstractItemView::setIndexWidget(d->index(item, column), widget);
}
and QAbstractItemView::setIndexWidget:
void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget)
{
Q_D(QAbstractItemView);
if (!d->isIndexValid(index))
return;
if (QWidget *oldWidget = indexWidget(index)) {
d->persistent.remove(oldWidget);
d->removeEditor(oldWidget);
oldWidget->deleteLater();
}
so if you add slider0 two times, then at first call it was added,
at seconds call Qt call for it deleteLater, and then added it,
are sure that this is what you want?
You have to set correct parent in the constructor of QTreeWidgetItem. Try this:
QTreeWidgetItem* item0 = new QTreeWidgetItem(treewidget);
Also it is important to understand who is owner of the slider0 after calling of setItemWidget(): the owner is your table, so 1) you don't need to delete this object; 2) the object will be deleted if you call setItemWidget for the same cell again. So, double call of treewidget->setItemWidget(item0, 0, slider0); seems very strange (second time you are setting the deleted object into that cell).

Parse Issue - expected unqualified id

Hey guys this is my code and i am relatively new to C++ and even coding really dont know why i am getting a parse error
though i as per my understanding i have placed the parenthesis properly anyone please suggest if i am missing anything here.
i am getting error at this line
class getProcessor()->RequestUIUpdate()// UI update must be done each time a new editor is constructed
Full Code:
StereoWidthCtrlAudioProcessorEditor::StereoWidthCtrlAudioProcessorEditor (StereoWidthCtrlAudioProcessor* ownerFilter)
: AudioProcessorEditor(ownerFilter)
{
addAndMakeVisible (WidthCtrlSld = new Slider ("Width Factor Slider"));
WidthCtrlSld->setRange (0, 5, 0.1);
WidthCtrlSld->setSliderStyle (Slider::LinearHorizontal);
WidthCtrlSld->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20);
WidthCtrlSld->addListener (this);
addAndMakeVisible (BypassBtn = new TextButton ("Bypass Button"));
BypassBtn->setButtonText (TRANS("Bypass"));
BypassBtn->addListener (this);
addAndMakeVisible (label = new Label ("new label",
TRANS("Stereo Width Factor:")));
label->setFont (Font (15.00f, Font::plain));
label->setJustificationType (Justification::centredLeft);
label->setEditable (false, false, false);
label->setColour (Label::textColourId, Colour (0xffa34747));
label->setColour (TextEditor::textColourId, Colours::black);
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
//[UserPreSize]
//[/UserPreSize]
setSize (600, 400);
//[Constructor] You can add your own custom stuff here..
class getProcessor()->RequestUIUpdate()// UI update must be done each time a new editor is constructed
startTimer(200)//starts timer with interval of 200mS
BypassBtn->setClickingTogglesState(true);
//[/Constructor]
}
StereoWidthCtrlAudioProcessorEditor::~StereoWidthCtrlAudioProcessorEditor()
{
//[Destructor_pre]. You can add your own custom destruction code here..
//[/Destructor_pre]
WidthCtrlSld = nullptr;
BypassBtn = nullptr;
label = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]enter code here
}
class is a keyword mainly used in declarations. You probably meant:
getProcessor()->RequestUIUpdate();

MFC VC++ Custom Checkbox Image

How do I get a 3-state checkbox to use a different bitmap for the Indeterminate state?
I want to change the image used by my 3-state checkboxes to use a different one; the controls are in Win98-style, and the indeterminate state of such checkboxes is difficult to distinguish from disabled checkboxes (this is presumably why they changed this for the WinXP-style controls, but I cannot use those because of other details in my project).
I'm using Visual C++ 2010, and I've defined an 8x8 bitmap in VS's Resource Editor. The bitmap's ID is IDB_INDET_CHECK.
I'm not entirely sure what the standard "technique" for something like this is; I've only really just started getting into manipulating Windows controls and MFC.
My first attempt was to create a class, CTriButton, that derives from CButton, override the DrawItem function, and try to draw it myself. I then used SubclassDlgItem to turn one of the checkboxes in my window into this class (I think?). This... sort of works? The checkbox no longer appears, and if I click on where it should be, an empty checkbox frame appears, but nothing else happens (and the debug message in my code is not being sent).
Here's the relevant code, though I'm not sure any of this is right. First, code from my window's OnInitDialog.
BOOL CAffixFilterDlg::OnInitDialog() // CAffixFilterDlg is my CDialog-derived window
{
CDialog::OnInitDialog(); // call basic version
// subclass a CButton-derived control with CTriButton
if ( CBipedHead.SubclassDlgItem(IDC_HEAD, this) ) // CBipedHead is a CTriButton member of CAffixFilterDlg, IDC_HEAD is a checkbox
SetWindowLong(CBipedHead.m_hWnd, GWL_STYLE, CBipedHead.GetStyle() | BS_OWNERDRAW); // set the ownerdraw style
else // subclassing didn't work
_ERROR("Subclassing failed."); // I do not see this error message, so SubclassDlgItem worked?
// initialization continues, but is not relevant...
UpdateWindow();
Invalidate();
return TRUE;
}
Next, the code for my custom button's DrawItem.
void CTriButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
_DMESSAGE("Drawing TriButton"); // never see this message
CDC dc;
dc.Attach(lpDrawItemStruct->hDC); //Get device context object
int nWidth = GetSystemMetrics(SM_CXMENUCHECK);
int nMargin = ( nWidth - 8 ) / 2;
CRect textRt = lpDrawItemStruct->rcItem;
textRt.right = textRt.right - nWidth - nMargin;
CString text;
GetWindowText(text);
UINT textDrawState = DST_TEXT;
if ( lpDrawItemStruct->itemState & ODS_DISABLED )
textDrawState |= DSS_DISABLED;
dc.DrawState(CPoint(textRt.left, textRt.top), textRt.Size(), text, textDrawState, TRUE, 0, (CBrush*)NULL);
CRect rt = lpDrawItemStruct->rcItem; // initial rect is for entire button
rt.left = rt.right - nWidth; // set left margin
LONG center = ( rt.bottom + rt.top ) / 2;
rt.top = center - nWidth/2;
rt.bottom = center + nWidth/2;
UINT checkDrawState = DFCS_BUTTONCHECK;
if ( lpDrawItemStruct->itemState & ODS_DISABLED )
checkDrawState |= DFCS_INACTIVE;
if ( lpDrawItemStruct->itemState & ODS_CHECKED )
checkDrawState |= DFCS_CHECKED;
else if ( GetCheck() == BST_INDETERMINATE ) {
_VMESSAGE("Indeterminate; custom draw.");
CBitmap indet_check = CBitmap();
indet_check.LoadBitmap(IDB_INDET_CHECK);
CPoint pt = CPoint(rt.left + nMargin, rt.top + nMargin);
CSize sz = CSize(8, 8);
dc.DrawState(pt, sz, &indet_check, DST_BITMAP|DSS_NORMAL);
}
dc.DrawFrameControl(rt, DFC_BUTTON, checkDrawState);
}
In OnInitDialog() you need to call InvalidateRect() after changing the window style otherwise it doesn't know it needs to be redrawn. It's also a good idea to call UpdateWindow() after changing window styles. Some information is usually cached by the common controls and won't acknowledge the change until UpdateWindow() has been called.
In DrawItem() you are responsible for rendering all states of the control. You should not call CButton::DrawItem() as it does nothing. Try something like the following:
void CTriButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CBitmap indet_check
_DMESSAGE("Drawing TriButton"); // I never see this message
int checkState = GetCheck();
if ( checkState == BST_CHECKED )
{
indet_check.LoadBitmap(IDB_INDET_CHECK);
}
else if ( checkState == BST_UNCHECKED )
{
indet_check.LoadBitmap(IDB_INDET_UNCHECKED);
}
else if ( checkState == BST_INDETERMINATE )
{
indet_check.LoadBitmap(IDB_INDET_INDETERMINATE);
}
// ... rest of your drawing code here ...
// don't forget to draw focus and push states too ;)
}
Addendum:
I can't believe I missed this first time around but your call to SubclassDlgItem is probably not having the desired effect. This call causes messages intended for the button to be processed by the controls parent window first. Because the default implementation of DrawItem in CWnd (the superclass of CDialog) does nothing the message never gets passed to the control.
Replace this with the following snippet and everything should be ok:
HWND hWndButton;
GetDlgItem(IDC_HEAD, &hWndButton);
CBipedHead.SubclassWindow(hWndButton);
Two side notes here:
It's usually not a good idea to use the same naming convention for both classes and class members. It makes for a confusing read.
I'm guessing you are always compiling and running in release mode. If you are - don't. This prevents assertions from being thrown and letting you know something is wrong.
Not the answer, but an answer: this custom CCheckBox I found more-or-less enables what I want. It doesn't, by default, allow 3 states, but I fixed that up with some of my own tweaks. I'm not 100% sure it works out of the box (I've had some issues, that don't seem to be due to my edits, but I can't be sure), but it was the solution I've used. I'm not going to call this the answer, though, in case someone can spy what was wrong with my code and wants to illuminate me.