My problem is that I just can't seem to make my QSlider work with double values instead of integer, because I need to make it return double values to a QLineEdit and also set it's own value when I put some value in the edit.
When I was a Qt beginner I started with this tutorial. It is a little bit old (it refers to Qt4.1), but it was good enough to get me started!
I have put together a simple example application that can show you where to start... Maybe you can find it helpful!
#include <QApplication>
#include <QtGui>
#include <QVBoxLayout>
#include <QSlider>
#include <QLabel>
class DoubleSlider : public QSlider {
Q_OBJECT
public:
DoubleSlider(QWidget *parent = 0) : QSlider(parent) {
connect(this, SIGNAL(valueChanged(int)),
this, SLOT(notifyValueChanged(int)));
}
signals:
void doubleValueChanged(double value);
public slots:
void notifyValueChanged(int value) {
double doubleValue = value / 10.0;
emit doubleValueChanged(doubleValue);
}
};
class Test : public QWidget {
Q_OBJECT
public:
Test(QWidget *parent = 0) : QWidget(parent),
m_slider(new DoubleSlider()),
m_label(new QLabel())
{
m_slider->setOrientation(Qt::Horizontal);
m_slider->setRange(0, 100);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(m_slider);
layout->addWidget(m_label);
connect(m_slider, SIGNAL(doubleValueChanged(double)),
this, SLOT(updateLabelValue(double)));
updateLabelValue(m_slider->value());
}
public slots:
void updateLabelValue(double value) {
m_label->setText(QString::number(value, 'f', 2));
}
private:
QSlider *m_slider;
QLabel *m_label;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Test *wid = new Test();
wid->show();
return a.exec();
}
#include "main.moc"
You can simply divide slider value on some constant. For example:
const int dpi = 10; // Any constant 10^n
int slideVal = 57; // Integer value from slider
double realVal = double( slideVal / dpi ); // float value
Related
I'm using a custom QTableView with a custom QAbstractTableModel and a QItemDelegate. I'd need to access the contents of the delegate's editor while the user is editing it, and after several attempts, I couldn't find anything satisfying.
Indeed, I've tried several things.
First: trying to access the delegate's current input (created through createEditor) through a property defined in QItemDelegate but... it seems that none exists. That's why I tried to add a QWidget* editor property and setting it in the createEditor.
Unfortunately, QItemDelegate's createEditor is supposed to be const, which makes me unable to set my property there (and since I don't control what calls createEditor, I can't do it before or after).
I don't really know what to do here. Actually, I also needed to know when the user started (or stopped) editing the cell content, which I eventually achieved by creating two const signals (editingStarted and editingStopped). I could probably create a const editorOpened(QWidget*) signal but it just feels bad and ugly...
I can't believe nothing "official" exists to achieve what I'm trying to do, hence this question. If I have everything wrong from the beginning, I'd be glad to know. If you have any other ideas, please suggest.
EDIT: Here is a minimal working example
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include <QTableView>
#include "mytableview.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
auto tableView = new MyTableView(this);
setCentralWidget(tableView);
}
MainWindow::~MainWindow()
{
}
MyItemDelegate.h
#ifndef MYITEMDELEGATE_H
#define MYITEMDELEGATE_H
#include <QItemDelegate>
#include <QLineEdit>
#include <QStandardItemModel>
class MyItemDelegate : public QItemDelegate
{
Q_OBJECT
public:
MyItemDelegate(QObject* parent);
virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual void onCloseEditor();
virtual ~MyItemDelegate() = default;
signals:
// Const signals trick
void editingStarted() const;
void editingFinished() const;
void editorOpened(const QWidget*) const;
};
#endif // MYITEMDELEGATE_H
MyItemDelegate.cpp
#include "myitemdelegate.h"
MyItemDelegate::MyItemDelegate(QObject* parent) : QItemDelegate(parent)
{
connect(this, &QItemDelegate::closeEditor, this, &MyItemDelegate::onCloseEditor);
}
QWidget* MyItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
auto lineEdit = new QLineEdit(parent);
emit editingStarted();
emit editorOpened(lineEdit);
return lineEdit;
}
void MyItemDelegate::onCloseEditor()
{
emit editingFinished();
}
MyTableView.h
#ifndef MYTABLEVIEW_H
#define MYTABLEVIEW_H
#include <QTableView>
#include <QDebug>
#include "myitemdelegate.h"
class MyTableView : public QTableView
{
Q_OBJECT
public:
explicit MyTableView(QWidget *parent = nullptr);
signals:
public slots:
};
#endif // MYTABLEVIEW_H
MyTableView.cpp
#include "mytableview.h"
MyTableView::MyTableView(QWidget *parent) : QTableView(parent)
{
MyItemDelegate* delegate = new MyItemDelegate(this);
QStandardItemModel* model = new QStandardItemModel(this);
setItemDelegate(delegate);
setModel(model);
QList<QList<QStandardItem*>> items;
for(int i = 0; i < 10; i++)
{
items << QList<QStandardItem*>();
for (int j = 'A'; j < 'E'; j++)
items[i] << new QStandardItem(QString("%1,%2").arg(i).arg(static_cast<char>(j)));
}
for (const auto& row : items)
model->appendRow(row);
connect(delegate, &MyItemDelegate::editingStarted, []() {
qDebug() << "Editing started";
});
connect(delegate, &MyItemDelegate::editingFinished, []() {
qDebug() << "Editing finished";
});
connect(delegate, &MyItemDelegate::editorOpened, [](const QWidget* editor) {
auto lineEdit = qobject_cast<const QLineEdit*>(editor);
connect(lineEdit, &QLineEdit::textChanged, [](const QString& text) {
qDebug() << text;
});
});
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
The following solution maybe fits your needs. I just defined a new signal inside the delegate and connected to it inside the class owning the delegate.
MyItemDelegate.h
#ifndef MYITEMDELEGATE_H
#define MYITEMDELEGATE_H
#include <QStyledItemDelegate>
class MyItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
MyItemDelegate(QObject* parent);
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual ~MyItemDelegate() = default;
signals:
void valueChanged(const QString&);
};
#endif // MYITEMDELEGATE_H
MyItemDelegate.cpp
#include "myitemdelegate.h"
#include <QLineEdit>
MyItemDelegate::MyItemDelegate(QObject* parent) : QStyledItemDelegate(parent)
{
}
QWidget* MyItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
auto lineEdit = new QLineEdit(parent);
connect(lineEdit, &QLineEdit::textChanged, this, &MyItemDelegate::valueChanged);
return lineEdit;
}
MyTableView.cpp
#include "mytableview.h"
#include <QStandardItemModel>
MyTableView::MyTableView(QWidget *parent) : QTableView(parent)
{
MyItemDelegate* delegate = new MyItemDelegate(this);
QStandardItemModel* model = new QStandardItemModel(this);
setItemDelegate(delegate);
setModel(model);
QList<QList<QStandardItem*>> items;
for(int i = 0; i < 10; i++)
{
items << QList<QStandardItem*>();
for (int j = 'A'; j < 'E'; j++)
items[i] << new QStandardItem(QString("%1,%2").arg(i).arg(static_cast<char>(j)));
}
for (const auto& row : items)
model->appendRow(row);
connect(delegate, &MyItemDelegate::valueChanged, [](auto v) { qDebug() << v; });
}
I am looking for an easy way to link hand coded design to the UI for widgets applications in Qt. I plan to use the UI builder to easily adjust the layouts and obtain proper spacing, which I find hard to do without the UI builder.
I want to create a 3x3 grid of buttons for which I plan to use QVector< QVector<QPushButton*> > (I am not sure how I would do this in UI builder.)
Here is what I have tried, Why are the buttons not displayed even when I set the parent of each button to the widget ?
main.cpp
#include "window.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QPushButton>
namespace Ui {
class Window;
}
class Window : public QWidget
{
Q_OBJECT
public:
explicit Window(QWidget *parent = 0);
~Window();
private:
Ui::Window *ui;
static const int tiles = 50, height = 600, width = 500;
QVector< QVector<QPushButton*> > cells;
};
#endif // WINDOW_H
window.cpp
#include "window.h"
#include "ui_window.h"
Window::Window(QWidget *parent) :
QWidget(parent),
ui(new Ui::Window)
{
ui->setupUi(this);
this->resize(width, height);
int j = 0;
for(auto &row : cells)
{
int i = 0;
for(auto &col : row)
{
col = new QPushButton(this);
col->setGeometry(i, j, tiles, tiles);
i += tiles;
}
j += tiles;
}
}
Window::~Window()
{
delete ui;
for(auto &row : cells)
{
for(auto &col : row)
{
delete col;
}
}
}
Any help would be appreciated.
The vectors are empty, so you iterate over nothing. Instead of managing these manually, you could leverage the grid layout.
Alas, you're complicating things unnecessarily with all the manual memory management and geometry management. It's unnecessary. All you need to do is to add widgets to the layout you allude to. And even then, I don't see how relegating the layout to a .ui file helps you since there the layout must be empty. So yes: you can set spacings, but you won't see them until you run the code. So it seems like a pointless exercise, unless you have other elements you're not telling us about (why aren't you - you went so far already).
Below is a minimum example that simplifies it as much as practicable, but see this answer and the links therein for more idea.
// https://github.com/KubaO/stackoverflown/tree/master/questions/button-grid-43214317
#include <QtWidgets>
namespace Ui { class Window {
public:
// Approximate uic output
QGridLayout *layout;
void setupUi(QWidget * widget) {
layout = new QGridLayout(widget);
}
}; }
class Window : public QWidget
{
Q_OBJECT
Ui::Window ui;
QPushButton * buttonAt(int row, int column) {
auto item = ui.layout->itemAtPosition(row, column);
return item ? qobject_cast<QPushButton*>(item->widget()) : nullptr;
}
public:
explicit Window(QWidget *parent = {});
};
Window::Window(QWidget *parent) : QWidget(parent) {
ui.setupUi(this);
for (int i = 0; i < 5; ++i)
for (int j = 0; j < 6; ++j)
{
auto b = new QPushButton(QStringLiteral("%1,%2").arg(i).arg(j));
ui.layout->addWidget(b, i, j);
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
#include "main.moc"
I have been trying to use Qt5 to give me an OpenGL context, which I believe it does, but when I try to call glewInit() from within the initializeGL function, the error returns back "Missing GL version," which I have been led to believe indicates that there is no valid context. The solution I saw was to call glewInit() from within initializeGL... but I'm already doing that.
I am setting the clear color and clearing to dark red to verify that gl calls are working, which they appear to be.
Any suggestions?
main.c
#define QT_NO_OPENGL_ES_2
#include <QApplication>
#include "glwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GLWidget w;
w.show();
return a.exec();
}
glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <GL/glew.h>
#define QT_NO_OPENGL_ES_2
#include <QGLWidget>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
explicit GLWidget(QGLWidget *parent = 0);
~GLWidget();
QSize minimumSizeHint() const;
QSize sizeHint() const;
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
};
#endif // GLWIDGET_H
glwidget.cpp
#include "glwidget.h"
GLWidget::GLWidget(QGLWidget *parent) :
QGLWidget(parent)
{
}
GLWidget::~GLWidget() {}
QSize GLWidget::minimumSizeHint() const {
return QSize(640, 480);
}
QSize GLWidget::sizeHint() const {
return QSize(800, 600);
}
void GLWidget::initializeGL() {
GLenum err = glewInit();
if (GLEW_OK != err) {
printf("GLEW error: %s\n", glewGetErrorString(err));
} else {
printf("Glew loaded; using version %s\n", glewGetString(GLEW_VERSION));
}
glClearColor(0.2f, 0, 0, 1.0f);
}
void GLWidget::resizeGL(int w, int h) {
}
void GLWidget::paintGL() {
glClear( GL_COLOR_BUFFER_BIT );
}
Something tells me this is because of the QGLWidget's default QGLFormat using OpenGL version 1.0 (Looking through GLEW's change logs, it seems the earliest version they claim to fully support is 1.5) . Try instead to override the QGLWidget constructor that requires a QGLFormat and pass it an instance of QGLFormat that uses the version you are targeting.
The call to your widget should look something like:
QGLFormat format;
format.setVersion(3,3); // or whatever version you are targeting.
format.setDoubleBuffer(true);
GLWidget * widget = new GLWidget(format);
I have a Qt dialog and there is a slider in it, when the dialog is initialized the slider will be set a value. In order to remind the user what is the default value, I want to add a mark to the slider, just draw a line or a triangle above the handle. Here, the slider should be of QSlider type, that means I can't implement a customized control derived from QSlider. Is there any way to realize it ?
I'm not clear why you can't derive a control from QSlider. You can still treat it like a QSlider, just override the paintEvent method. The example below is pretty cheesy, visually speaking, but you could use the methods from QStyle to make it look more natural:
#include <QtGui>
class DefaultValueSlider : public QSlider {
Q_OBJECT
public:
DefaultValueSlider(Qt::Orientation orientation, QWidget *parent = NULL)
: QSlider(orientation, parent),
default_value_(-1) {
connect(this, SIGNAL(valueChanged(int)), SLOT(VerifyDefaultValue(int)));
}
protected:
void paintEvent(QPaintEvent *ev) {
int position = QStyle::sliderPositionFromValue(minimum(),
maximum(),
default_value_,
width());
QPainter painter(this);
painter.drawLine(position, 0, position, height());
QSlider::paintEvent(ev);
}
private slots:
void VerifyDefaultValue(int value){
if (default_value_ == -1) {
default_value_ = value;
update();
}
}
private:
int default_value_;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
DefaultValueSlider *slider = new DefaultValueSlider(Qt::Horizontal);
slider->setValue(30);
QWidget *w = new QWidget;
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(slider);
layout->addStretch(1);
w->setLayout(layout);
QMainWindow window;
window.setCentralWidget(w);
window.show();
return app.exec();
}
#include "main.moc"
Easiest way I can think off is:
Add QSlider to QSlider (like you do it with layouts and QFrames). Slider above will be your current slider (clickable one). Slider below will be your "default tick position" value.
#include <QApplication>
#include <QSlider>
#include <QVBoxLayout>
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
QSlider * defaultValueSlider = new QSlider();
QSlider * valueSlider = new QSlider(defaultValueSlider);
QVBoxLayout * lay = new QVBoxLayout(defaultValueSlider);
lay->setContentsMargins(0, 0, 0, 0);
lay->setSpacing(0);
lay->addWidget(valueSlider);
defaultValueSlider->setRange(0, 100);
valueSlider->setRange(0, 100);
defaultValueSlider->setValue(30);
defaultValueSlider->show();
return app.exec();
}
Why do you need to inherit a QSlider to access its public methods?
http://doc.trolltech.com/4.7/qslider.html
You can just call its setTickPosition() in your app.
I am trying to make a Collaborative Editor(I have to use Linux networking libraries for all the networking stuff), I have the main widget(custom made class that inherits QWidget) with all the components. In the constructor I create all the Widgets on this main Widget and at the end I try to create a new thread using QFuture(I use QFuture instead of QThread cause it allows me easily to call functions with any type of parameters, like QTextEdit, QTextCursor...) but it gives me this error at compilation:
"QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTextDocument(0x1b064b0), parent's thread is QThread(0x1985750), current thread is QThread(0x1ae7610)".
How to solve the error?
Here is my code:
mainwindow.h:
...//includes
using namespace QtConcurrent;
...
namespace Ui {
class Widget;
class TextEdit;
}
class TextEdit;
class Widget;
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
...
QFuture<void> thread;
}
class TextEdit : public QTextEdit {
Q_OBJECT
...
}
static void receiveKeyPress(TextEdit *textedit, QTextCursor *secondUserCursor) {
unsigned long long int Number = NULL;
QMessageBox::information(textedit->parentWidget(), "UI Component", "This makes the thread to throw the error");
while(1) if(connected == 1) {
read(recvFileDescriptor, &Number, sizeof(unsigned long long int));
if( Number != NULL)
if( Number == Qt::Key_Home )
secondUserCursor->movePosition(QTextCursor::StartOfLine);
...
else {
QTextCharFormat backgroundFormat = textedit->textCursor().charFormat();
backgroundFormat.setBackground(QColor("lightGreen"));
//If I don't use QMessageBox up there, it breaks here on the next command
secondUserCursor->setCharFormat(backgroundFormat);
secondUserCursor->setPosition(textedit->textCursor().position());
secondUserCursor->insertText(QString::number(Number));
} //else
}//while
}//the function
And mainwindow.cpp:
#include "mainwindow.h"
Widget::Widget(QWidget *parent) {
...
thread = run(receiveKeyPress, this->edit1, this->edit1->secondUserCursor); //run is from QtConcurrent namespace
}
main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget window;
...
window.show();
return a.exec();
}
I've read here on stackoverflow how others use QObject(which I never used and I don't get the idea of it) and QThread(the only combination) but I already tried to use QThread and I wasn't able to pass QTextEdit and QTextCursor to it.
Thanks in advance
Edit:
mainwindow.h
class TextEdit : public QTextEdit {
Q_OBJECT
...
public slots:
void receiveKeyPress(qulonglong);
...
};
mainwindow.cpp
void TextEdit::receiveKeyPress(qulonglong Number) {
if( Number == Qt::Key_Home )
...
}
recv-thread.h - created based on this link http://developer.qt.nokia.com/doc/qt-4.8/thread-basics.html#example-3-clock
#include <QThread>
#include "mainwindow.h" //To get TextEdit in here
class RecvThread : public QThread {
Q_OBJECT
signals:
void transferDataToSlot(qulonglong Data);
protected:
void run();
};
recv-thread.cpp
#include "recv-thread.h"
void RecvThread::run() {
unsigned long long int Number = NULL;
while(1) if(connected == 1) {
read(recvFileDescriptor, &Number, sizeof(unsigned long long int));
if( Number != NULL) {
emit transferDataToSlot(Number);
}
}
}
main.cpp
...
#include "recv-thread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget window;
RecvThread recvThread;
...
QObject::connect(&recvThread, SIGNAL(transferDataToSlot(qulonglong)), window.edit1, SLOT(receiveKeyPress(qulonglong)), Qt::QueuedConnection); //line 38
recvThread.start();
//Displaying the window
window.show();
a.exec();
recvThread.quit();
recvThread.wait();
return 0;
}
Am I doing it right?