I'm looking to make a menu where there are more than one wxStaticTexts and when one of them is clicked it turns black and the rest are/revert back to being grey (if they were clicked before, otherwise they would just stay grey)
The problem is I usurped this code which works great for doing the first part, it turns the item that was clicked black, but it doesn't turn the rest back to grey. My attempt at a solution is in the else block. I haven't attempted anything else because I'm still figuring both C++ and WxWidgets out and I still don't have a complete understanding of some concepts used in this snippet.
void MyFrame::OnMenuTxtBtnLeftClickPanel(wxMouseEvent& event) {
wxObject* obj = event.GetEventObject();
wxPanel* objPanel = ((wxPanel*)obj);
wxWindowList objChild = objPanel->GetChildren();
for (wxWindowList::iterator it = objChild.begin(); it != objChild.end(); it++) {
wxStaticText* aStaticText = dynamic_cast<wxStaticText*>(*it);
if (aStaticText) {
aStaticText->SetForegroundColour(wxColour("#000000"));
}
else {
// Doesn't do anything when compiled
// it should change the StaticTexts that weren't clicked back to grey
dynamic_cast<wxStaticText*>(*it)->SetForegroundColour(wxColour("#C8C6C6"));
}
}
This works for me:
void MyFrame::OnMenuTxtBtnLeftClickPanel(wxMouseEvent& event)
{
wxWindow* cur = wxDynamicCast(event.GetEventObject(),wxWindow);
wxColor fg = m_panel1->GetForegroundColour();
wxWindowList& children = m_panel1->GetChildren();
for ( auto it = children.begin() ; it != children.end() ; ++it )
{
wxWindow* win = *it;
if ( wxDynamicCast(win, wxStaticText) )
{
if ( win == cur )
{
win->SetForegroundColour(wxColour("#000000"));
}
else
{
win->SetForegroundColour(fg);
}
}
}
}
In this code, m_panel1 is a wxPanel that is the parent of all the static texts.
On GTK, it looks like this:
The handler was bound to each static text control in the frame constructor like this:
m_staticText1->Bind(wxEVT_LEFT_UP,&MyFrame::OnMenuTxtBtnLeftClickPanel,this);
m_staticText2->Bind(wxEVT_LEFT_UP,&MyFrame::OnMenuTxtBtnLeftClickPanel,this);
m_staticText3->Bind(wxEVT_LEFT_UP,&MyFrame::OnMenuTxtBtnLeftClickPanel,this);
m_staticText4->Bind(wxEVT_LEFT_UP,&MyFrame::OnMenuTxtBtnLeftClickPanel,this);
m_staticText1, etc. should be changed to the names you're using for the text controls.
Related
So I'm having trouble with removing a QGraphicsPixMapItem. I add it to my view by setting it's parent so I expected that if I would change the parent to nullptr it would be removed but it didn't work. I read online that I could also use functions like hide but when I use these the program crashes. Whats the best way to fix this?
Btw I'm sure the code crashes when I call the hide function and the rest of my code is good.
A left click should add a 'stamlid' (QGraphicsPixMapItem) to the QGraphicsEllipsItem (this). And It should be removed with a right click.
void Vakje::mousePressEvent(QGraphicsSceneMouseEvent *event) {
Speler *speler = m_spel->getAanDeBeurt();
if (event->button() == Qt::LeftButton && m_stamlid == nullptr) {
m_stamlid = speler->getVrijeStamleden()[0]; //stamlid van speler dat niet op bord staat
m_stamlid->getStamlidView()->setParentItem(this);
m_stamlid->setOpBord(true);
m_stamlid->getStamlidView()->setVisible(true);
speler->getSpelerView()->updateMembers();
} else if (event->button() == Qt::RightButton && m_stamlid != nullptr) { //verwijder pion
m_stamlid->setOpBord(false);
m_stamlid->getStamlidView()->setParentItem(nullptr);
m_stamlid = nullptr;
speler->getSpelerView()->updateMembers();
}
}
The Qt documentation for the base class QGraphicsItem explains that setting the parent item to 0 does not remove the item, but makes it a top-level item instead.
Perhaps what you should do is get the item's scene and use it to remove the item.
if (m_stamlid->scene())
m_stamlid->scene()->removeItem(m_stamlid);
delete m_stamlid;
m_stamlid = nullptr;
I use C++ Builder 2009 and have implemented a Listview virtually.
Recently I learned of an issue that (so far) only happens for 3 people out of thousands. (Obviously there must be more instances, but they remain unreported so far).
What happens is that when the user hovers over the items in the ListView control, from bottom to top, the items in the list change.
Since the control is implemented virtually the software provides the information via an event and for 'a' reason the software gets the wrong index to work with when hovering from bottom to top.
See this little video to understand the behaviour better:
https://www.youtube.com/watch?v=jNZkaBH24PY
I have been searching for a reason, on and off, for some time, hampered by the fact that I cannot repeat this problem myself, so I needed to send special builds to 1 of the 3 willing to help. And I was finally able to pinpoint it to the use of Overlay icons !
I assign an icon to the items in the list by asking Windows what icon is relevant via SHGetFileInfo
The event:
void __fastcall TFinder::ListViewData(TObject *Sender, TListItem *Item)
{
DListView->OnData(Item, DirInListView->Object(Item->Index)) ;
}
Code called by the event:
HANDLE ObjectDisplayInListView::OnData (TListItem *ListItem, DataObject *Object)
{
ListItem->Data = (void*) Object ;
ListItem->Caption = String(Object->DisplayName().c_str()) ;
if (!SystemIconsSet)
{
ListItem->ImageIndex = Object->Icon() ;
ListItem->OverlayIndex = Object->IconOverlay() ;
}
else
{
int Icon = SystemIcon(Object) ;
ListItem->ImageIndex = (Icon & 0x00FFFFFF) ;
ListItem->OverlayIndex = (Icon >> 24) - 1 ;
}
ListItem->Cut = Object->IconGreyed() ;
ListItem->StateIndex = Object->IconState() ;
return (HANDLE) ListItem ;
}
// The SystemIcon() routine:
int ObjectDisplayInListView::SystemIcon (DataObject *Object)
{
// SHFILEINFO info ; The class declared one will do !
info.hIcon = NULL ; // Just making sure
DWORD Res = SHGetFileInfoW( Object->DisplayName().c_str(),
FILE_ATTRIBUTE_NORMAL,
&info,
sizeof(SHFILEINFO) ,
SHGFI_ICON |
SHGFI_USEFILEATTRIBUTES |
SHGFI_OVERLAYINDEX
) ;
DestroyIcon(info.hIcon) ;
return info.iIcon ;
}
The subclass code (which can be removed completely and the problem still exists !!)
void __fastcall TFinder::LVNewWindowProc(Messages::TMessage &Msg)
{
if( LVOldWindowProc ) LVOldWindowProc( Msg );
if (Msg.Msg == WM_NOTIFY) // Sort arrows
{
// Not relevant for this Q but added since it is in my code
switch(((LPNMHDR)Msg.LParam)->code)
{
case HDN_ENDTRACKA:
case HDN_ENDTRACKW:
case HDN_ITEMCHANGEDA:
case HDN_ITEMCHANGEDW:
{
if(((LPNMHDR)Msg.LParam)->hwndFrom == ListView_GetHeader(ListView->Handle))
{
if (ObjInListView && dynamic_cast<FileDirObject*>(ObjInListView) && ListView->Items->Count)
{
SetSortArrow(SortingTypeToDesignColumn(UISortingType), UISortingDirection) ; // Show the arrow based on what sorting was used
}
}
}
break;
}
}
else if (Msg.Msg == CN_NOTIFY && Platform > OS_PLATF_WINXP)
{
if (reinterpret_cast<LPNMHDR>(Msg.LParam)->code == LVN_GETDISPINFOW)
{
LV_ITEM &item = reinterpret_cast<LV_DISPINFO*>(Msg.LParam)->item ;
int OverlayIndex = -1 ;
TListItem *ListItem = ListView->Items->Item[item.iItem] ;
if (ListItem) OverlayIndex = ListItem->OverlayIndex ;
if (OverlayIndex >= 0)
{
item.mask |= LVIF_STATE ;
item.state |= INDEXTOOVERLAYMASK(OverlayIndex + 1) ;
item.stateMask |= LVIS_OVERLAYMASK ;
}
}
}
}
I implemented this based on an older question, asked here as well: Can't get Windows Overlay icons to work in TListView
To be more precise, this function has been working great for me for over 10 years, but about a year ago I added SHGFI_OVERLAYINDEX as well
The issue, as explained and as can be seen in the video, disappears entirely when I simply and only remove SHGFI_OVERLAYINDEX from the function call.
For whatever reason also asking for the overlay icon, causes the weird behaviour.
Even when I completely disable the CN_NOTIFY message subclassing that goes along with this functionality (see: Can't get Windows Overlay icons to work in TListView ) but call SHGetFileInfo() with SHGFI_OVERLAYINDEX, the problem happens !
Does anybody have an idea what this could be ?
A solution could be to not ask for the overlay icon on these problematic systems, but then I need to find a way to actually detect that the problem is going to happen (or is happening) somehow.
There are three messageboxes in the current scene, here I named them _grannyMessage, _grannyMessage2, _grannyMessage3 respectively. I want to make _grannyMessage disappear from the scene when _grannyMessage3 is created in the scene. I am trying to use the "this->removeChild(_grannyMessage);" function but it seems it's not working, am I calling the wrong function anyway? Thanks a lot
auto grannyListener = EventListenerTouchOneByOne::create();
grannyListener -> setSwallowTouches(true);
grannyListener -> onTouchBegan =[this](Touch *touch, Event *event){
MessageBoxes *_grannyMessage =
MessageBoxes::create("The hen can lay an egg everyday");
if(i==0){
_grannyMessage->setPosition(Vec2(600, 450));
addChild(_grannyMessage);
}
else if (i==1)
{
MessageBoxes *_grannyMessage2 =
MessageBoxes::create("2 yuan, that's all I can offer you for the hen");
_grannyMessage2->setPosition(Vec2(400, 450));
addChild(_grannyMessage2);
}
else if (i==2)
{
this->removeChild(_grannyMessage);
MessageBoxes *_grannyMessage3 =
MessageBoxes::create("Well");
_grannyMessage3->setPosition(Vec2(800, 450));
addChild(_grannyMessage3);
}
else
{
return false;
}
i++;
return false;
};
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(grannyListener, this);
It doesn't work because you create new _grannyMessage every time the user touches the screen and only the first one is added to the scene. Then with the third one you try to remove a child that is not on the screen (because it was just created, at the begining of the touch handler).
This happens because when the method ends, the _grannyMessage variable goes out of scope and is forgotten (the first one is retained though, as you added it to the scene).
To solve your problem, you need to store the first _grannyMessage, for example like this :
In *.h of your class add something like this inside your class :
private MessageBoxes *_grannyMessage;
Then change your touch handler to this :
grannyListener -> onTouchBegan =[this](Touch *touch, Event *event){
if(i==0){
MessageBoxes *_grannyMessage = MessageBoxes::create("The hen can lay an egg everyday");
_grannyMessage->setPosition(Vec2(600, 450));
this->_grannyMessage = _grannyMessage; // store the message that we want to remove;
addChild(_grannyMessage);
}
else if (i==1)
{
MessageBoxes *_grannyMessage2 =
MessageBoxes::create("2 yuan, that's all I can offer you for the hen");
_grannyMessage2->setPosition(Vec2(400, 450));
addChild(_grannyMessage2);
}
else if (i==2)
{
this->removeChild(this->_grannyMessage); //remove the stored message
MessageBoxes *_grannyMessage3 =
MessageBoxes::create("Well");
_grannyMessage3->setPosition(Vec2(800, 450));
addChild(_grannyMessage3);
}
else
{
return false;
}
i++;
return false;
};
Just a thought. Can you keep the same message pointer, and update the message label and position?
It might be something like this:
else if (i==2)
{
//_grannyMessage->clear(); // if clear() is available
_grannyMessage->setPosition(Vec2(800, 450)); // new position
_grannyMessage->setLable("New message"); // new message
}
In ActionScript, I can just check the .stage property of a DisplayObject, and if it's null, then the DisplayObject isn't on the display list. Is there a cocos2d equivalent?
I'm controlling my own touch system for buttons etc, and I want a quick way to ignore buttons that are registered but not actually on the screen. I'm currently checking against visible and parent, but that doesn't go all the way up the chain, so if I have a popup in memory that's not visible/attached to anything, and a button as a child inside that popup, the button check will pass (as it's visible and has a parent).
Aside from looping all the up until the scene, is there an easy way to check if a CCNode/CCSprite is on the display list?
Edit
Working on #HariKrishna's answer, this was the code I came up with as the cocos2d-x implementation wasn't exactly what I was looking for (e.g. if the parent of the node was nil, then it would return YES as it would never enter the check):
- (BOOL) hasVisibleParents
{
CCNode * p = self.parent;
while( true )
{
if( p == nil || !p.visible )
return NO;
if( [p isKindOfClass:[CCScene class]] )
return YES;
p = p.parent;
}
return YES;
}
You can use CCNode::isVisible() and CCControl::hasVisibleParents() which will internally go up to all the node hierarchy...
Thats the closest you can get for the same.
Example:
bool presentInDisplayList() {
if(isVisible() && hasVisibleParents())
return true;
else
return false;
}
Where hasVisibleParents() is, (Copied from Cocos2d-X Library)
bool CCControl::hasVisibleParents()
{
CCNode* pParent = this->getParent();
for( CCNode *c = pParent; c != NULL; c = c->getParent() )
{
if( !c->isVisible() )
{
return false;
}
}
return true;
}
This can be easily translated to Objective-C
I don't want mouse middle button to paste text in my QTextEdit. This code doesn't work. TextEdit inherits QTextEdit. After mouse middle button pastes it pastes copied text.
void TextEdit::mousePressEvent ( QMouseEvent * e ) {
if (e->button() == Qt::MidButton) {
e->accept();
return;
};
QTextEdit::mousePressEvent(e);
}
As mouse clicks are usually registered when the button is released, you should redefine the mouseReleaseEvent function.
You don't even need to redefine mousePressEvent, because the middle button isn't handled at all by that function.
I'm assuming you're using Linux here; right clicking in the window is likely to be triggering an insertion of mime data before you get to handle the mouse event, which is why it is still pasting text.
Therefore, according to Qt docs for paste: - " to modify what QTextEdit can paste and how it is being pasted, reimplement the virtual canInsertFromMimeData() and insertFromMimeData() functions."
I've been in the same case, that is to say: having parts of my CustomQTextEdit required to be non-editable.
As I truly love the middle mouse button paste feature, I did not wanted to disable it. So, here is the (more or less quick and dirty coded) workaround I used:
void QTextEditHighlighter::mouseReleaseEvent(QMouseEvent *e)
{
QString prev_text;
if (e->button() == Qt::MidButton) {
// Backup the text as it is before middle button click
prev_text = this->toPlainText();
// And let the paste operation occure...
// e->accept();
// return;
}
// !!!!
QTextEdit::mouseReleaseEvent(e);
// !!!!
if (e->button() == Qt::MidButton) {
/*
* Keep track of the editbale ranges (up to you).
* My way is a single one range inbetween the unique
* tags "//# BEGIN_EDIT" and "//# END_EDIT"...
*/
QRegExp begin_regexp = QRegExp("(^|\n)(\\s)*//# BEGIN_EDIT[^\n]*(?=\n|$)");
QRegExp end_regexp = QRegExp("(^|\n)(\\s)*//# END_EDIT[^\n]*(?=\n|$)");
QTextCursor from = QTextCursor(this->document());
from.movePosition(QTextCursor::Start);
QTextCursor cursor_begin = this->document()->find(begin_regexp, from);
QTextCursor cursor_end = this->document()->find(end_regexp, from);
cursor_begin.movePosition(QTextCursor::EndOfBlock);
cursor_end.movePosition(QTextCursor::StartOfBlock);
int begin_pos = cursor_begin.position();
int end_pos = cursor_end.position();
if (!(cursor_begin.isNull() || cursor_end.isNull())) {
// Deduce the insertion index by finding the position
// of the first character that changed between previous
// text and the current "after-paste" text
int insert_pos; //, end_insert_pos;
std::string s_cur = this->toPlainText().toStdString();
std::string s_prev = prev_text.toStdString();
int i_max = std::min(s_cur.length(), s_prev.length());
for (insert_pos=0; insert_pos < i_max; insert_pos++) {
if (s_cur[insert_pos] != s_prev[insert_pos])
break;
}
// If the insertion point is not in my editable area: just restore the
// text as it was before the paste occured
if (insert_pos < begin_pos+1 || insert_pos > end_pos) {
// Restore text (ghostly)
((MainWindow *)this->topLevelWidget())->disconnect(this, SIGNAL(textChanged()), ((MainWindow *)this->topLevelWidget()), SLOT(on_textEdit_CustomMacro_textChanged()));
this->setText(prev_text);
((MainWindow *)this->topLevelWidget())->connect(this, SIGNAL(textChanged()), ((MainWindow *)this->topLevelWidget()), SLOT(on_textEdit_CustomMacro_textChanged()));
}
}
}
}