n my App I use a QMDIArea. In this I open now a subclassed MDIChild that has a master class. Inside the master class I set the virtual changeEvent of the subwindow. But if I use this event I cannot move the window in the QMDIArea anymore and the sub window is not create in maximized.
If I remove the Event from the class it works again well. Do I use the Event the wrong way?
MdiChildBase.h
private:
virtual void changeEvent(QEvent * e);
MdiChildBase.cpp
void MdiChildBase::changeEvent(QEvent * e) {
if(e->type() == QEvent::WindowStateChange && this->isActiveWindow()) {
// .. this is now the active window
qDebug("Iam active now");
}
QWidget::changeEvent(e);
}
Ok after reading the docs and try something around the solution for this question is:
void MdiChildBase::changeEvent(QEvent * e) {
QMdiSubWindow::changeEvent(e);
if(e->type() == QEvent::WindowStateChange && this->isActiveWindow()) {
// .. this is now the active window
qDebug("Iam active now");
}
}
Related
I am making a windows forms app just to test out my designing skills, but I find that the outline is ugly, so I made my own Minimise and Close buttons, but I'm not sure how to make a pannel that you can drag around. Can anyone help me?
By the way, the code is C#.
Using events we can take the current location when we leftclick (MouseDown) and on MouseMove, we take the current window location minus where we were before and add the distance we've dragged our mouse.
public partial class Form1 : Form
{
private Point windowLocation;
public Form1()
{
InitializeComponent();
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
this.windowLocation = e.Location;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// Refers to the Form location (or whatever you trigger the event on)
this.Location = new Point(
(this.Location.X - windowLocation.X) + e.X,
(this.Location.Y - windowLocation.Y) + e.Y
);
this.Update();
}
}
}
I have implemented the panning view on the QGraphicsView, using the mouse move event using
void View::mouseMoveEvent(QMouseEvent* event) {
pan();
QGraphicsView::mouseMoveEvent(event);
}
and in the scene of this view I have added few items where some of the items are resizable, so I implemented
void Item::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if(m_resizeMode)
{
resize();
e->accept();
}
}
I tried to filter the mouse move not to propagate to any further using e->accept()
but my View mouseMove event has been called first , so when ever I tried to resize the item, the view started to pan all the way.
How can I avoid this event propagation from view to scene.
You can call the base class implementation of the QGraphicsView and check if the event is accepted. However I would do this in the mousePressEvent instead of the mouseMoveEvent. After all this is where you determine if you should resize an item or do some panning. This is how I do something similar in my project:
void View::mousePressEvent(QMouseEvent *event)
{
...
QGraphicsView::mousePressEvent(event);
if(event->isAccepted())
move = false;
else
move = true;
}
void View::mouseMoveEvent(QMouseEvent *event)
{
if(!move)
{
QGraphicsView::mouseMoveEvent(event);
return;
}
... // you would do the panning here
QGraphicsView::mouseMoveEvent(event);
}
void View::mouseReleaseEvent(QMouseEvent *event)
{
if(!move)
{
QGraphicsView::mouseReleaseEvent(event);
return;
}
else
{
...
move = false;
}
QGraphicsView::mouseReleaseEvent(event);
}
The view will always receive the mouse event first.
So, in the view, check to see if the mouse is over an item before allowing it to pan by getting the mouse pos in scene coordinates and retrieving the items at that position with QGraphicsScene::items( )
During my override of OnActivate() in my view-model, I need to call GetView() in order to focus an element. When I do this after I have previously activated my view, it's fine. But when I call this the first activation, it fails.
I was able to get it to work by swapping a few lines in ConductorBaseWithActiveItem.ChangeActiveItem. The original is as follows:
protected virtual void ChangeActiveItem(T newItem, bool closePrevious) {
ScreenExtensions.TryDeactivate(activeItem, closePrevious);
newItem = EnsureItem(newItem);
if(IsActive)
ScreenExtensions.TryActivate(newItem);
activeItem = newItem;
NotifyOfPropertyChange("ActiveItem");
OnActivationProcessed(activeItem, true);
}
and with my changes:
protected virtual void ChangeActiveItem(T newItem, bool closePrevious) {
ScreenExtensions.TryDeactivate(activeItem, closePrevious);
newItem = EnsureItem(newItem);
activeItem = newItem;
NotifyOfPropertyChange("ActiveItem");
if (IsActive)
ScreenExtensions.TryActivate(newItem);
OnActivationProcessed(activeItem, true);
}
This seems to work. Notifying that "ActiveItem" changed triggers the code to load and cache the view. Then ScreenExtensions.TryActivate calls my OnActivate override.
Question: I haven't noticed any problems doing this, but I'm curious if anyone knows better than I do what repercussions this change could have?
Thanks!
One thing you could try is overriding Caliburn's OnViewAttached method and trying to focus it there. That being said, in MVVM, focus is more of a View concern, so if possible, that logic should be moved from the ViewModel to the View.
One way you may be able to solve this is by creating an attached behavior (you will need a reference to the Microsoft.Expression.Interactions assembly):
public class FocusWhenVisibleBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
this.AssociatedObject.Loaded += this.Loaded;
this.AssociatedObject.IsVisibleChanged += this.VisibleChanged;
}
protected override void OnDetaching()
{
this.AssociatedObject.Loaded -= this.Loaded;
this.AssociatedObject.IsVisibleChanged -= this.VisibleChanged;
}
private void Loaded(object sender, RoutedEventArgs e)
{
this.TryFocus();
}
private void VisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
this.TryFocus();
}
private void TryFocus()
{
if (this.AssociatedObject.IsLoaded && this.AssociatedObject.IsVisible)
{
// Focus the control
this.AssociatedObject.Focus();
}
}
}
And that attaching that behavior to whatever control you want to focus:
<Button>
<i:Interaction.Behaviors>
<b:FocusWhenVisibleBehavior/>
</i:Interaction.Behaviors>
</Button>
I am using QMouseEvent and QKeyEvents in my program. I programmatically make various widgets (QDockWidgets and QCustomPlots).
I would like to use a single click and keypress handler function. However, I am struggling to get the widget that is actually being clicked, so that I can do certain stuff within that widget.
Is there a way to return from a ClickEvent the name of the widget that was clicked?
You can implement eventFilter in your mainWindow and listen for events from widgets there :
bool MainWindow::eventFilter(QObject * obj, QEvent * event)
{
if((myWidget *)obj == widget1 && event->type()==QEvent::KeyPress)
{
int pressedKey = ((QKeyEvent*)event)->key();
...
}
else if((myWidget *)obj == widget2 && event->type()==QEvent::MouseButtonRelease)
{
if(((QMouseEvent*)event)->button() == Qt::LeftButton)
{
...
}
}
return false;
}
Also do not forget to install event filters for your widgets in the mainWindow constructor :
widget1->installEventFilter(this);
widget2->installEventFilter(this);
Focus events don't work because they're not sent if you activate your window by clicking on its non-client frame. Also, if you click the internal components of the window THEY will get the focus event, not your window, but the window will still be activated, even if it wasn't active or focused before.
The event you want is QEvent::WindowActivate. Override event() to process it:
bool YourWidget::event(QEvent *e)
{
if (e->type() == QEvent::WindowActivate) {
// window was activated
}
return QWidget::event(e);
}
Qt provides several virtual event handling functions you can use. Since the activation of a window changes its state, you want to handle some change events:
void MyWidget::changeEvent(QEvent * e) {
if(e->type() == QEvent::ActivationChange && this->isActiveWindow()) {
// .. this is now the active window
}
}
References
changeEvent
isActiveWindow