There are 4 areas on my LED Ring and I made 4 buttons for choosing them.
I want to be able to use these areas for different combinations.
So my aim is:
One click on the button: Selected area is active.
Double click on on the button: Selected area is deactive.
I know there is a function called mousePressed() but I couldn't implement it to my buttons with a double-click condition.
Here is the piece of my code of from processing:
Group AreaGroup = cp5.addGroup("AREAS")
.setPosition(290,50)
.setWidth(150)
.setHeight(30)
.setFont(font2)
.moveTo(SetupGroup);
background(0);
noStroke();
;
cp5.addButton("AREA_1") // The button
.setPosition(-15,10) // x and y relative to the group
.setSize(90, 50) // (width, height)
.setFont(font)
.moveTo(AreaGroup); // add it to the group
;
cp5.addButton("AREA_2") // The button
.setPosition(90,10) // x and y relative to the group
.setSize(90, 50) // (width, height)
.setFont(font)
.moveTo(AreaGroup); // add it to the group
;
cp5.addButton("AREA_3") // The button
.setPosition(-15,80) // x and y relative to the group
.setSize(90, 50) // (width, height)
.setFont(font)
.moveTo(AreaGroup); // add it to the group
;
cp5.addButton("AREA_4") // The button
.setPosition(90,80) // x and y relative to the group
.setSize(90, 50) // (width, height)
.setFont(font)
.moveTo(AreaGroup); // add it to the group
;
cp5.addButton("ALL") // The button
.setPosition(190,45) // x and y relative to the group
.setSize(90, 50) // (width, height)
.setFont(font)
.moveTo(AreaGroup); // add it to the group
;
void AREA_1(){
println("AREA_1");
if (port != null) port.write("a\n");
}
void AREA_2(){
println("AREA_2");
if (port != null) port.write("b\n");
}
void AREA_3(){
println("AREA_3");
if (port != null) port.write("c\n");
}
void AREA_4(){
println("AREA_4");
if (port != null) port.write("d\n");
}
void ALL(){
println("ALL");
if (port != null) port.write("t\n");
}
And here is the code pieces from Arduino
switch(state){
case 'p':
Serial.println(F("ex."));
break;
case 's':
Serial.println(F("Start"));
start = true;
break;
case '1':
Serial.println(F("Switching to ring #1"));
updateRing1 = true;
updateRing2 = false;
break;
case '2':
Serial.println(F("Switching to ring #2"));
updateRing1 = false;
updateRing2 = true;
break;
case 'a':
Serial.println(F("Area1"));
Area1 = true;
break;
case 'b':
Serial.println(F("Area2"));
Area2 = true;
break;
case 'c':
Serial.println(F("Area3"));
Area3 = true;
break;
case 'd':
Serial.println(F("Area4"));
Area4 = true;
break;
case 't':
Serial.println(F("All the leds are choosen"));
total = true;
Area1 = false;
Area2 = false;
Area3 = false;
Area4 = false;
break;
If you intend to detect double clicks, start a millis() timer at the first click, then take a second millis() reading after the second click and compare it to a time threshold to detect it. You will need a couple of timing variables, one for the current value and another one for storing the previous one.
What did you try exactly with the mousePressed() function? It would be nice to know what you have tried and where you failed in order to help you
Related
I make my own class from QWidget with redefine of paintEvent(), mousePressEvent(), mouseReleaseEvent() and mouseMoveEvent(). All that methods for move widgets over other widget (yellow).
When i create my widgets in a layout, it looks like this:
But when I move black widget to the bottom and red to the top like this:
and resize window, all widgets refresh to their align positions:
But i want, when i move one widget higher then another, the widgets should align in layout in new places, like this:
Which function i should redefine to do it?
P.S.
There is a piece of code, that can move widgets positions inside layout (change their indexes), but i don't know how find out their (x,y) position to calculate new indexes in layout. I think, that i can do it in resizeEvent().
But it when it event was emitted, positions already changed to old. (like before moveing on 1 picture), and i need positions after moveing (like on secon picture). How can i get position of widget before it will be aligned?
or How can i change order of widget in layout by drag and drop with the mouse?
I write my own widget, then redefine following methods: mouseReleaseEvent(), paintEvent(), mousePressEvent(), mouseMoveEvent(). In mousePressEvent() I hold old X and Y positions and mouse position on figure. Then in mouseMoveEvent() i calculate if minimum distance of mouse move is riched and move widget to new position (it not moves widget index in layout). After it, if emitted mouseReleaseEvent() i just calculate new index of moving widget and change and update parent layout. If widget moves less then it height, then layout just updates without changing widget index.
void SimpleWidget::mouseMoveEvent(QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton))
return;
if (!IsMinimumDistanceRiched(event))
{
return;
}
int y = event->globalY() - mouseClickY + oldY;
int BottomBorder = parentWidget->geometry().height() - this->geometry().height();
if(y < 0) y = 0;
else if(y > BottomBorder) y = BottomBorder;
move(oldX, y);
}
void SimpleWidget::mousePressEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
dragStartPosition = event->pos();
oldX = this->geometry().x();
oldY = this->geometry().y();
mouseClickX = event->globalX();
mouseClickY = event->globalY();
}
bool SimpleWidget::IsMinimumDistanceRiched(QMouseEvent *event)
{
return (event->pos() - dragStartPosition).manhattanLength() >= QApplication::startDragDistance();
}
bool SimpleWidget::moveInLayout(QWidget *widget, MoveDirection direction)
{
QVBoxLayout* myLayout = qobject_cast<QVBoxLayout*>(widget->parentWidget()->layout());
const int index = myLayout->indexOf(widget);
if (direction == MoveUp && index == 0)
{
return false;
}
if (direction == MoveDown && index == myLayout->count()-1 )
{
return false;
}
const int newIndex = direction == MoveUp ? index - 1 : index + 1;
myLayout->removeWidget(widget);
myLayout->insertWidget(newIndex , widget);
return true;
}
void SimpleWidget::paintEvent(QPaintEvent *)
{
QStyleOption o;
o.initFrom(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
}
void SimpleWidget::mouseReleaseEvent(QMouseEvent *)
{
int y = geometry().y();
MoveDirection direct;
int offset;
if(oldY > y)
{
offset = oldY - y;
direct = MoveUp;
}
else if(oldY < y)
{
offset = y - oldY;
direct = MoveDown;
}
int count = offset/height();
for(int i = 0; i < count; i++)
{
moveInLayout(this, direct);
}
update();
QVBoxLayout* myLayout = qobject_cast<QVBoxLayout*>(this->parentWidget->layout());
myLayout->update();
this->saveGeometry();
}
Can someone please share the algorithm to rotate and resize a QGraphicsLineItem present on a QGraphicsScene? I wish to be able to click on either end of the line and rotate it while the opposite end automatically becomes the anchor point for rotation.
I have tried the solution given below and it works brilliantly!!. The solution is for line rotation only. This solution is provided to me when i posted the question at other Qt platform. All the credit goes to original author who provided the solution to me.
void Line::mousePressEvent( QGraphicsSceneMouseEvent * event ){
const QPointF pos = event->pos();
const qreal l1 = QLineF( pos, this->line().p1() ).length();
const qreal l2 = QLineF( pos, this->line().p2() ).length();
const qreal threshold = 3.5;
if( l1 < l2 and l1 < threshold ){
_dragIndex = 1;
} else if ( l2 < l1 and l2 < threshold ){
_dragIndex = 0;
} else{
_dragIndex = -1;
}
event->setAccepted( _dragIndex != -1 );
}
void Line::mouseMoveEvent( QGraphicsSceneMouseEvent * event ){
if( _dragIndex != -1 ){
const QPointF anchor = _dragIndex == 0 ? this->line().p1() : this->line().p2();
QLineF ma = QLineF(anchor,event->pos());
ma.setLength( line().length() );
const QPointF rotated = anchor + QPointF( ma.dx(), ma.dy() );
this->setLine( _dragIndex == 0 ? QLineF(anchor,rotated) : QLineF(rotated,anchor) );
}
}
void Line::mouseReleaseEvent( QGraphicsSceneMouseEvent * event ){
_dragIndex = -1;
QGraphicsLineItem::mouseReleaseEvent(event);
}
1- Overload mouseMoveEvent of your scene. Make sure you are in the initial state, no clicks, nothing. If position is close enough to the ends, set your flag as such.
// scene.cpp
void mouseMoveEvent(QMouseEvent *e){
if(moveToRotate){
lineItem->rotate(flag, e->pos());
...
return;
}
if(isClose(e->pos(), lineItem->firstEnd)
flag = 1;
else if(isClose(e->pos(), lineItem->secondEnd)
flag = 2;
else
flag = 0;
return;
}
2- Overload mouseClickEvent of the scene. If flag is set (1 or 2), get your anchor point. You can overload paint method of lineItem to highlight the end point. Also set firstClick flag.
void mouseClickEvent(QMouseEvent *e){ // firstClick happened
if(flag !=0){ //process click
firstClick = true;
paintAnchor = true;
moveToRotate = true;
}
else // neglect click
return;
return;
}
// myCustomLineItemclassThatInheritsQGraphicsLineItem.cpp
void paint(... ){
if(paintAnchor){
...
}
}
There are obvious errors, but the general flow should be as such. You may need a signal to connect the boolean to the paint event of another class. You may need to overload mouseReleaseEvent to properly set moveToRotate. And, of course rotate and isClose methods are yours to be written -maybe even exist in the API.
Just construct the main flowchart, it will help you a lot.
I am trying to implement a game using opengl in qt4. So far I have created the football pitch and I am now trying to implement a camera with which the user can move in the world freely using the arrow keys. My friend used a piece of code he found on NeHe's tutorials and simply copy pasted it to his code and the camera worked for him. When I tried the same only the escape button works and it just closes the opengl widget. f1 key is supposed to switch to fullscreen but it just makes the mouse cursor invisible without switching to fullscreen mode. The arrow keys don't work at all. As I'm new to opengl I could not figure out what is wrong with the implementation.
I'm adding the code where I draw the pitch and also the keyboard event handlers.
void metinalifeyyaz::paintGL(){
movePlayer();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
GLfloat xtrans = -xpos;
GLfloat ytrans = -walkbias - 0.50f;
GLfloat ztrans = -zpos;
GLfloat sceneroty = 360.0f - yrot;
glLoadIdentity();
glRotatef(lookupdown, 1.0f, 0.0f, 0.0f);
glRotatef(sceneroty, 0.0f, 1.0f, 0.0f);
glTranslatef(xtrans, ytrans+50, ztrans-130);
glLoadIdentity();
glTranslatef(1.0f,0.0f,-18.0f);
glRotatef(45,1,0,0);
drawScene();
int delay = time.msecsTo(QTime::currentTime());
if (delay == 0)
delay = 1;
time = QTime::currentTime();
timer->start(qMax(0,10 - delay));
}
void metinalifeyyaz::movePlayer() {
if (keyUp) {
xpos -= sin(yrot * PI_OVER_180) * 0.5f;
zpos -= cos(yrot * PI_OVER_180) * 0.5f;
if (walkbiasangle >= 360.0f)
walkbiasangle = 0.0f;
else
walkbiasangle += 7.0f;
walkbias = sin(walkbiasangle * PI_OVER_180) / 10.0f;
} else if (keyDown) {
xpos += sin(yrot * PI_OVER_180)*0.5f;
zpos += cos(yrot * PI_OVER_180)*0.5f ;
if (walkbiasangle <= 7.0f)
walkbiasangle = 360.0f;
else
walkbiasangle -= 7.0f;
walkbias = sin(walkbiasangle * PI_OVER_180) / 10.0f;
}
if (keyLeft)
yrot += 0.5f;
else if (keyRight)
yrot -= 0.5f;
if (keyPageUp)
lookupdown -= 0.5;
else if (keyPageDown)
lookupdown += 0.5;
}
void metinalifeyyaz::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_Escape:
close();
break;
case Qt::Key_F1:
setWindowState(windowState() ^ Qt::WindowFullScreen);
break;
default:
QGLWidget::keyPressEvent(event);
case Qt::Key_PageUp:
keyPageUp = true;
break;
case Qt::Key_PageDown:
keyPageDown = true;
break;
case Qt::Key_Left:
keyLeft = true;
break;
case Qt::Key_Right:
keyRight = true;
break;
case Qt::Key_Up:
keyUp = true;
break;
case Qt::Key_Down:
keyDown = true;
break;
}
}
void metinalifeyyaz::changeEvent(QEvent *event) {
switch (event->type()) {
case QEvent::WindowStateChange:
if (windowState() == Qt::WindowFullScreen)
setCursor(Qt::BlankCursor);
else
unsetCursor();
break;
default:
break;
}
}
void metinalifeyyaz::keyReleaseEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_PageUp:
keyPageUp = false;
break;
case Qt::Key_PageDown:
keyPageDown = false;
break;
case Qt::Key_Left:
keyLeft = false;
break;
case Qt::Key_Right:
keyRight = false;
break;
case Qt::Key_Up:
keyUp = false;
break;
case Qt::Key_Down:
keyDown = false;
break;
default:
QGLWidget::keyReleaseEvent(event);
}
}
I know that copy paste is not an efficient method but my friend's project is not different than mine and it works for him. If you know anything that might cause the same code to work on one project and not the other please point it out. Of course any other comment about the code are much appreciated.
Look:
glLoadIdentity();
glRotatef(lookupdown, 1.0f, 0.0f, 0.0f);
glRotatef(sceneroty, 0.0f, 1.0f, 0.0f);
glTranslatef(xtrans, ytrans+50, ztrans-130);
glLoadIdentity(); // get rid of this!
glTranslatef(1.0f,0.0f,-18.0f);
glRotatef(45,1,0,0);
drawScene();
"glLoadIdentity" resets the current matrix. In your code, you rotate and translate the matrix, but afterward, you reset the matrix by calling "glLoadIdentity", so the previous matrix transformations do nothing.
Basically this is your code:
OpenGL, reset the matrix.
OpenGL, move the player and camera.
OpenGL, reset the matrix, and forget anything I just did.
OpenGL, do... whatever that is.
OpenGL, draw my scene!
I try to lock mouse cursor movements to the left half of the screen. I have following screen setup:
On the left side is a Qt window of size 1120x1080, on the right side a GL window of size 800x1080.
I use Openbox window manager under Ubuntu 12.10. The window layout stays fixed.
I need to restrict mouse movement to the Qt window.
To get the mouse to stay in the window, enable mouse movement with:
setMouseTracking(true);
and override void QWidget::mouseMovement( QMouseEvent * event )
void TheWindow::mouseMoveEvent ( QMouseEvent * event )
{
// get window size without frame
QRect s = geometry();
// get current cursor position
int x = event->globalX();
int y = event->globalY();
bool reset = false;
// Check cursor position relative to window
if (event->x() < 0)
{
x -= event->x();
reset = true;
}
else if (event->x() >= s.width())
{
x += s.width() - event->x() - 1;
reset = true;
}
if (event->y() < 0)
{
y -= event->y();
reset = true;
}
else if (event->y() >= s.height())
{
y += s.height() - event->y() - 1;
reset = true;
}
// if reset needed move cursor
if (reset) QCursor::setPos(x,y);
}
this involving QGraphicsItem::itemChange(). If you have an item which you want to restrict to a certain area then reimplement itemChange() for that item and monitor QGraphicsItem::ItemPositionHasChanged changes to see whether the items wants to be placed outside your area of interest and prevent that by returning a position from inside that area. for example:
QVariant QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
switch (change) {
case ItemPositionHasChanged:
if(x() < -200 || y() < -200 || x() > 200 || y() > 200)
setPos(0, 0);
graph->itemMoved();
break;
default:
break;
};
return QGraphicsItem::itemChange(change, value);
}
I need to draw curves with Qt: The user clicks on QGraphicsScene (via QGraphicsView) and straight lines are drawn between the points clicked on by the user. When the user finishes to draw straight lines (by clicking on the right button), the set of lines becomes a curve.
For that, I need to use the QPainterPath::cubicTo(...) method and add the path to the QGraphicsScene using QGraphicsScene::addPath(...).
The problem is that I don't know how to compute the parameter values that are passed to cubicTo(...).
For example, in the following picture, the user has drawn the two gray lines by clicking points A B and C. When she clicks the right button, I want to draw the red line using cubicTo(...):
My current code only draws gray lines because I have set c1, c2, d1 and d2 values to point positions clicked on by the user :
void Visuel::mousePressEvent(QMouseEvent *event)
{
int x = ((float)event->pos().x()/(float)this->rect().width())*(float)scene()->sceneRect().width();
int y = ((float)event->pos().y()/(float)this->rect().height())*(float)scene()->sceneRect().height();
qDebug() << x << y;
if(event->button() == Qt::LeftButton)
{
path->cubicTo(x,y,x,y,x,y);
}
if(event->button() == Qt::RightButton)
{
if(path == NULL)
{
path = new QPainterPath();
path->moveTo(x,y);
}
else
{
path->cubicTo(x,y,x,y,x,y);
scene()->addPath(*path,QPen(QColor(79, 106, 25)));
path = NULL;
}
}
}
Apparently control points c1, c2, d1, d2 are just coordinates of point B in your picture. In more general case point C lies on AB line and point D lies on BC line.
In Qt code this can be written as follows:
Visuel class should have the following properties:
QPoint A, B, C;
unsigned int count;
Which should be initialized in Visuel's constructor.
void Visuel::Visuel()
{
count = 0;
// Initialize other stuff as well
}
Then we are going to overload QGraphicsScene::mousePressEvent() to detect user's mouse events:
void Visuel::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
/* Ignore everything else except left button's press */
if (event->type() != QEvent::GraphicsSceneMousePress ||
event->button() != Qt::LeftButton) {
return;
}
switch (count) {
case 0:
A = event->scenePos();
break;
case 1: {
B = event->scenePos();
/* Draw AB line */
QPainterPath path(A);
path.lineTo(B);
scene()->addPath(path, Qt::grey);
}
break;
case 2: {
C = event->scenePos();
/* Draw BC line */
QPainterPath path(B);
path.lineTo(C);
scene()->addPath(path, Qt::grey);
/* Draw ABBC cubic Bezier curve */
QPainterPath path2(A);
path2.cubicTo(B, B, C);
scene()->addPath(path2, Qt::red);
}
break;
default:
break;
}
if (count >= 2) {
count = 0;
} else {
count++;
}
}