I use fitInView() function to view the image pixels, but image pixels exists offset, how to solve this problem?
void QtGraphicsView::setViewRect(const QRectF &rect)
{
if (m_viewRect == rect)
return;
m_viewRect = rect;
fitInView(rect);
}
void QtGraphicsView::scaleView(qreal factor)
{
const QSizeF &size = m_viewRect.size() / factor;
if (size.width() <= 0 || size.height() <= 0
|| size.width() >= sceneRect().width()
|| size.height() >= sceneRect().height())
return;
const QSizeF &dsize = m_viewRect.size() - size;
const QPointF &topLeft = m_viewRect.topLeft()
+ QPointF(dsize.width() / 2, dsize.height() / 2);
setViewRect(QRectF(topLeft, size).toRect());
}
Related
I have written a small program that renders a 175x175 heightmap. The rendering is done using Qt3D which is basically a set of wrappers around OpenGL. The program loads fine and runs fine on a powerful desktop. However, when I run it on a lower power GPU, image updates are very choppy when I start moving the camera around. Rendering 3D terrain mesh really shouldn't be that difficult for even a small GPU, so I assume I am doing something very wrong. Are there some obvious ways to optimize this code or am I just expecting too much from a small GPU?
Fragment shader
https://github.com/qt/qt3d/blob/5.12/src/extras/shaders/es2/phong.inc.frag
Vertex shader:
https://github.com/qt/qt3d/blob/5.12/src/extras/shaders/es2/morphphong.vert
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
Qt3DExtras::Qt3DWindow view;
// Scene Root
Qt3DCore::QEntity *sceneRoot = new Qt3DCore::QEntity();
// Scene Camera
Qt3DRender::QCamera *basicCamera = view.camera();
basicCamera->setProjectionType(Qt3DRender::QCameraLens::PerspectiveProjection);
basicCamera->setUpVector(QVector3D(0.0f, 1.0f, 0.0f));
basicCamera->setViewCenter(QVector3D(60.0f, 15.0f, -60.0f));
basicCamera->setPosition(QVector3D(60.0f, 26.0f, 0.0f));
// For camera controls
Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(sceneRoot);
camController->setCamera(basicCamera);
// Material
Qt3DRender::QMaterial *material= new Qt3DExtras::QPhongMaterial(sceneRoot);
Qt3DCore::QEntity *customMeshEntity = new Qt3DCore::QEntity(sceneRoot);
// Transform
Qt3DCore::QTransform *transform = new Qt3DCore::QTransform;
Qt3DRender::QGeometryRenderer *customMeshRenderer = new Qt3DRender::QGeometryRenderer;
Qt3DRender::QGeometry *customGeometry = new Qt3DRender::QGeometry(customMeshRenderer);
Qt3DRender::QBuffer *vertexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, customGeometry);
Qt3DRender::QBuffer *indexDataBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, customGeometry);
QImage heightmap("../assets/heightmap.png");
QByteArray vertexBufferData;
vertexBufferData.resize(heightmap.width() * heightmap.height() * (3 + 3 + 3) * sizeof(float));
QVector<QVector3D> vertexPositions;
for (int row = 0; row < heightmap.height(); row++) {
for (int column = 0; column < heightmap.width(); column++) {
vertexPositions.append(QVector3D(row, heightmap.pixelColor(row, column).red()/8.0, -column));
}
}
QVector<QVector3D> vertexNormals;
for (int row = 0; row < heightmap.height(); row++) {
for (int column = 0; column < heightmap.width(); column++) {
int center = (row * heightmap.width()) + column;
int upper = center - heightmap.width();
int lower = center + heightmap.width();
int right = center + 1;
int left = center -1;
int lowerLeft = center - 1 + heightmap.width();
int upperRight = center + 1 - heightmap.width();
int rightEdge = heightmap.width() - 1;
int bottomEdge = heightmap.height() -1;
// Calculate normals for each adjacent face and sum
// Check for edge conditions
QVector3D vertexNormal(0, 0, 0);
if (column != 0 && row != 0 ) {
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[upper], vertexPositions[left]);
}
if (column != rightEdge && row != 0) {
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[upperRight], vertexPositions[upper]);
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[right], vertexPositions[upperRight]);
}
if (column != rightEdge && row != bottomEdge) {
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[lower], vertexPositions[right]);
}
if (column != 0 && row != bottomEdge) {
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[lowerLeft], vertexPositions[lower]);
vertexNormal += QVector3D::normal(vertexPositions[center], vertexPositions[left], vertexPositions[lowerLeft]);
}
vertexNormals.append(vertexNormal.normalized());
}
}
// Colors
QVector3D red(1.0f, 0.0f, 0.0f);
QVector3D yellow(1.0f, 1.0f, 0.0f);
QVector3D green(0.0f, 1.0f, 0.0f);
QVector3D blue(0.0f, 0.0f, 1.0f);
QVector3D white(1.0f, 1.0f, 1.0f);
QVector<QVector3D> vertices;
for (int i = 0; i < vertexPositions.count(); i ++) {
vertices.append(vertexPositions[i]);
vertices.append(vertexNormals[i]);
if (vertexPositions[i].y() > 20.0) {
vertices.append(red);
}
else if (vertexPositions[i].y() > 18.0) {
vertices.append(yellow);
}
else {
vertices.append(green);
}
}
float *rawVertexArray = reinterpret_cast<float *>(vertexBufferData.data());
int idx = 0;
Q_FOREACH (const QVector3D &v, vertices) {
rawVertexArray[idx++] = v.x();
rawVertexArray[idx++] = v.y();
rawVertexArray[idx++] = v.z();
}
// Indices
QByteArray indexBufferData;
int indicesCount = (heightmap.height() - 1) * (heightmap.width() - 1) * 2 * 3;
indexBufferData.resize( indicesCount * sizeof(uint));
uint *rawIndexArray = reinterpret_cast<uint *>(indexBufferData.data());
int index = 0;
for (int row = 0; row < heightmap.height()-1; row++) {
for (int column = 0; column < heightmap.width()-1; column++) {
// 1 <- 3
// | /
// | /
// v /
// 2
int vertexBufferIndex = (row * heightmap.width()) + column;
rawIndexArray[index++] = vertexBufferIndex;
rawIndexArray[index++] = vertexBufferIndex + heightmap.width(); // down one row
rawIndexArray[index++] = vertexBufferIndex + 1; // right one column
// 1
// / ^
// / |
// / |
// 2 -> 3
rawIndexArray[index++] = vertexBufferIndex + 1; // right one column
rawIndexArray[index++] = vertexBufferIndex + heightmap.width(); // down one row
rawIndexArray[index++] = vertexBufferIndex + heightmap.width() + 1; // down one row and right one column
}
}
vertexDataBuffer->setData(vertexBufferData);
indexDataBuffer->setData(indexBufferData);
// Attributes
Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute();
positionAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute);
positionAttribute->setBuffer(vertexDataBuffer);
positionAttribute->setDataType( Qt3DRender::QAttribute::Float);
positionAttribute->setDataSize(3);
positionAttribute->setByteOffset(0);
positionAttribute->setByteStride(9 * sizeof(float));
positionAttribute->setCount(vertexPositions.count());
positionAttribute->setName( Qt3DRender::QAttribute::defaultPositionAttributeName());
Qt3DRender::QAttribute *normalAttribute = new Qt3DRender::QAttribute();
normalAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute);
normalAttribute->setBuffer(vertexDataBuffer);
normalAttribute->setDataType( Qt3DRender::QAttribute::Float);
normalAttribute->setDataSize(3);
normalAttribute->setByteOffset(3 * sizeof(float));
normalAttribute->setByteStride(9 * sizeof(float));
normalAttribute->setCount(vertexPositions.count());
normalAttribute->setName( Qt3DRender::QAttribute::defaultNormalAttributeName());
Qt3DRender::QAttribute *colorAttribute = new Qt3DRender::QAttribute();
colorAttribute->setAttributeType( Qt3DRender::QAttribute::VertexAttribute);
colorAttribute->setBuffer(vertexDataBuffer);
colorAttribute->setDataType( Qt3DRender::QAttribute::Float);
colorAttribute->setDataSize(3);
colorAttribute->setByteOffset(6 * sizeof(float));
colorAttribute->setByteStride(9 * sizeof(float));
colorAttribute->setCount(vertexPositions.count());
colorAttribute->setName( Qt3DRender::QAttribute::defaultColorAttributeName());
Qt3DRender::QAttribute *indexAttribute = new Qt3DRender::QAttribute();
indexAttribute->setAttributeType( Qt3DRender::QAttribute::IndexAttribute);
indexAttribute->setBuffer(indexDataBuffer);
indexAttribute->setDataType( Qt3DRender::QAttribute::UnsignedInt);
indexAttribute->setDataSize(1);
indexAttribute->setByteOffset(0);
indexAttribute->setByteStride(0);
indexAttribute->setCount(indicesCount);
customGeometry->addAttribute(positionAttribute);
customGeometry->addAttribute(normalAttribute);
customGeometry->addAttribute(colorAttribute);
customGeometry->addAttribute(indexAttribute);
customMeshRenderer->setInstanceCount(1);
customMeshRenderer->setFirstVertex(0);
customMeshRenderer->setFirstInstance(0);
customMeshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
customMeshRenderer->setGeometry(customGeometry);
customMeshEntity->addComponent(customMeshRenderer);
customMeshEntity->addComponent(transform);
customMeshEntity->addComponent(material);
view.setRootEntity(sceneRoot);
view.show();
return app.exec();
}
The Qt blog has a very good write-up on optimizing Qt3D applications for low-end hardware.
https://blog.qt.io/blog/2019/04/02/optimizing-real-time-3d-entry-level-hardware/
I have data from a camera in mono 8bit.
This is converted into an int vector using
std::vector<int> grayVector(size);
// convert / copy pointer data into vector: 8 bit
if (static_cast<XI_IMG_FORMAT>(format) == XI_MONO8)
{
quint8* imageIterator = reinterpret_cast<quint8*> (pMemVoid);
for (size_t count = 0; count < size; ++count)
{
grayVector[count] = static_cast<int>(*imageIterator);
imageIterator++;
}
}
Next, I need to convert this into a QImage. If I set the image format to QImage::Format_Mono the app crashes. With QImage::Format_RGB16 I get strippes, and with QImage::Format_RGB32 everything is black.
I would like to know how to do this the best, efficient and correct way?
// convert gray values into QImage data
QImage image = QImage(static_cast<int>(sizeX), static_cat<int>(sizeY), QImage::Format_RGB16);
for ( int y = 0; y < sizeY; ++y )
{
int yoffset = sizeY*y;
QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y)) ;
for ( int x = 0; x < sizeX ; ++x )
{
int pos = x + yoffset;
int color = grayVector[static_cast<size_t>(pos)];
*line++ = qRgb(color, color, color);
}
}
The conversion to int is unnecessary and you do it in a very inefficient way; all you need is to use the QImage::Format_Grayscale8 available since Qt 5.5 (mid-2015).
Anyway, what you really want is a way to go from XI_IMG to QImage. The default BP_UNSAFE buffering policy should be adequate - the QImage will do a format conversion, so taking the data from XiApi's internal buffer is OK. Thus the following - all of the conversions are implemented in Qt and are quite efficient - much better than most any naive code.
I didn't check whether some Xi formats may need a BGR swap. If so, then the swap can be set to true in the format selection code and the rest will happen automatically.
See also: xiAPI manual.
static QVector<QRgb> grayScaleColorTable() {
static QVector<QRgb> table;
if (table.isEmpty()) {
table.resize(256);
auto *data = table.data();
for (int i = 0; i < table.size(); ++i)
data[i] = qRgb(i, i, i);
}
return table;
}
constexpr QImage::Format grayScaleFormat() {
return (QT_VERSION >= QT_VERSION_CHECK(5,5,0))
? QImage::Format_Grayscale8
: QImage::Format_Indexed8;
}
QImage convertToImage(const XI_IMG *src, QImage::Format f) {
Q_ASSERT(src->fmt == XI_MONO16);
Q_ASSERT((src->padding_x % 2) == 0);
if (src->fmt != XI_MONO16) return {};
const quint16 *s = static_cast<const quint16*>(src->bp);
const int s_pad = src->padding_x/2;
if (f == QImage::Format_BGR30 ||
f == QImage::Format_A2BGR30_Premultiplied ||
f == QImage::Format_RGB30 ||
f == QImage::Format_A2RGB30_Premultiplied)
{
QImage ret{src->width, src->height, f};
Q_ASSERT((ret->bytesPerLine() % 4) == 0);
const int d_pad = ret->bytesPerLine()/4 - ret->width();
quint32 *d = (quint32*)ret.bits();
if (s_pad == d_pad) {
const int N = (src->width + s_pad) * src->height - s_pad;
for (int i = 0; i < N; ++i) {
quint32 const v = (*s++) >> (16-10);
*d++ = 0xC0000000 | v << 20 | v << 10 | v;
}
} else {
for (int j = 0; j < src->height; ++j) {
for (int i = 0; i < src->width; ++i) {
quint32 const v = (*s++) >> (16-10);
*d++ = 0xC0000000u | v << 20 | v << 10 | v;
}
s += s_pad;
d += d_pad;
}
}
return ret;
}
QImage ret{src->width, src->height, grayScaleFormat()};
const int d_pad = ret->bytesPerLine() - ret->width();
auto *d = ret.bits();
if (s_pad == d_pad) {
const int N = (src->width + s_pad) * src->height - s_pad;
for (int i = 0; i < N; ++i) {
*d++ = (*s++) >> 8;
} else {
for (int j = 0; j < src->height; ++j) {
for (int i = 0; i < src->width; ++i)
*d++ = (*s++) >> 8;
s += s_pad;
d += d_pad;
}
}
return ret;
}
QImage fromXiImg(const XI_IMG *src, QImage::Format dstFormat = QImage::Format_ARGB32Premultiplied) {
Q_ASSERT(src->width > 0 && src->height > 0 && src->padding_x >= 0 && src->bp_size > 0);
Q_ASSERT(dstFormat != QImage::Format_Invalid);
bool swap = false;
int srcPixelBytes = 0;
bool externalConvert = false;
QImage::Format srcFormat = QImage::Format_Invalid;
switch (src->fmt) {
case XI_MONO8:
srcPixelBytes = 1;
srcFormat = grayScaleFormat();
break;
case XI_MONO16:
srcPixelBytes = 2;
externalConvert = true;
break;
case XI_RGB24:
srcPixelBytes = 3;
srcFormat = QImage::Format_RGB888;
break;
case XI_RGB32:
srcPixelBytes = 4;
srcFormat = QImage::Format_RGB32;
break;
};
if (srcFormat == QImage::Format_Invalid && !externalConvert) {
qWarning("Unhandled XI_IMG image format");
return {};
}
Q_ASSERT(srcPixelBytes > 0 && srcPixelBytes <= 4);
int bytesPerLine = src->width * srcPixelBytes + src->padding_x;
if ((bytesPerLine * src->height - src->padding_x) > src->bp_size) {
qWarning("Inconsistent XI_IMG data");
return {};
}
QImage ret;
if (!externalConvert)
ret = QImage{static_cast<const uchar*>(src->bp), src->width, src->height,
bytesPerLine, srcFormat};
else
ret = convertToImage(src, dstFormat);
if (ret.format() == QImage::Format_Indexed8)
ret.setColorTable(grayScaleColorTable());
if (ret.format() != dstFormat)
ret = std::move(ret).convertToFormat(dstFormat);
if (swap)
ret = std::move(ret).rgbSwapped();
if (!ret.isDetached()) // ensure that we don't share XI_IMG's data buffer
ret.detach();
return ret;
}
I have a custom line item which is subclassed from QGraphicsLineItem. When mouse move event occurs on the line item edge, I rotate or resize the line accordingly. My problem is that before perfroming rotation or resizing, the line item exists in local coordinate system with P1(0,0) and P2(x,y).
When P2 is used as anchor for resizing and rotating and mouse is placed on P1, the P1 takes the mouse event->pos() cordinates. Once the resize is done, I need to transform the line item to a local coordinate system. How do I do that? I tried using setTransformOriginPoint(event->pos()) but it doesnt translate my P1 to origin.
The code used for rotation/resize is as follows:
void CustomGraphicsLineItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
qDebug()<<"Line mouse move event";
if( dragIndex != -1 )
{
const QPointF anchor = dragIndex == 0 ? this->line().p1() : this->line().p2();
this->setLine(dragIndex == 0 ? QLineF(anchor, event->pos()) : QLineF(event->pos(),anchor));
}
if(dragIndex == 1)
{
this->setTransformOriginPoint(event->pos());
}
this->update();
}
void CustomGraphicsLineItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
qDebug()<<"Line mouse press event";
// initialPos = mapToScene(event->pos());
dragIndex = -1;
const QPointF event_pos = event->pos();
const qreal l1 = QLineF( event_pos, this->line().p1() ).length();
const qreal l2 = QLineF( event_pos, this->line().p2() ).length();
//threshold indicates the area of influence of the mouse click event, which is set to 5.0 pixels
const qreal threshold = 15.0;
if(l1 < threshold || l2 < threshold)
{
if( l1 < l2 && l1 < threshold )
{
dragIndex = 1;
}
else if ( l2 < l1 && l2 < threshold )
{
dragIndex = 0;
}
else
{
dragIndex = -1;
}
event->setAccepted( dragIndex != -1 );
}
//if we click anywhere other than the end points, then consider it to be a drag
if(l1 > threshold && l2 > threshold)
{
QMimeData * mimeData = new QMimeData;
CustomGraphicsLineItem * item = this;
QByteArray byteArray(reinterpret_cast<char*>(&item),sizeof(CustomGraphicsLineItem*));
mimeData->setData("Item",byteArray);
// start the event
QDrag * drag = new QDrag(event->widget());
drag->setMimeData(mimeData);
drag->exec();
dragStart = event->pos();
event->accept();
}
}
void CustomGraphicsLineItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
dragIndex = -1;
QGraphicsLineItem::mouseReleaseEvent(event);
}
void CustomGraphicsLineItem::paint (QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
// qDebug() << "CustomGraphicsLineItem::paint called ";
QPen pen=QPen();
pen.setColor(Qt::red);
pen.setWidth(5);
painter->setPen(pen);
painter->setBrush(Qt::red);
painter->setRenderHint(QPainter::Antialiasing);
painter->drawLine(line());
}
I am writing a game. By tick timer should work the this slot.
void game_process::animate_cell(MainWindow* m, const std::string& s, double x,double y, size_t i, size_t j, const std::string& step)
{
painter.begin(m);
std::string ss("C:\\Users\\Vardan\\GAmes_lines\\res\\red_" + step + ".png");
ss += s;
const char* p = ss.c_str();
QImage image(p);
RECT temp = cal
culate_cell_rect(i, j);
QRectF target(x, y, image.width(), image.height());
painter.drawImage(target, image);
painter.end();
m->update(x + temp.x0, y + temp.y0, 60, 60);
}
, that's it,
QTimer * timer = new QTimer (this);
connect (timer, SIGNAL (timeout ()), this, SLOT (render_cell (MainWindow * m, const std :: string & s, double x, double y, size_t i, size_t j, const std :: string & step))); timer-> start ();
But as you can see the slot more parameters than the signal, and hence signals and slots mechanism does not work. What to do?
Here cod
#include <QDesktopWidget>
#include <QResizeEvent>
#include <QDebug>
#include <QTimer>
#include <QTime>
#include <phonon/MediaObject>
#include <phonon/MediaSource>
#include <phonon/AudioOutput>
#include <utility>
#include <cassert>
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent)
{
QImage image("C:\\Users\\Vardan\\GAmes_lines\\res\\back_3.png");
m_width = 1000;
m_height = 800;
m_game_width = image.width();
m_game_height = image.height();
setFixedSize(m_width, m_height);
m_click_coords.first = 0;
m_click_coords.second = 0;
m_timer_tick = false;
m_timer_id = 0;
setWindowFlags( Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
m_area_x0_coordinate = (this->width() - image.width())/2;
m_area_y0_coordinate = (this->height() - image.height())/2;
m_r = new game_process(m_area_x0_coordinate, m_area_y0_coordinate, image.width()/*+30*/, image.height()/*+30*/, 57);
m_status = false;
Phonon::MediaObject *mediaobject = new Phonon::MediaObject;
QString filename("C://Users//Vardan//GAmes_lines//music//Casino Ambiance Music.wav");
mediaobject->setCurrentSource(filename);
Phonon::AudioOutput *audio = new Phonon::AudioOutput;
Phonon::createPath(mediaobject,audio);
mediaobject->play();
QPixmap pixmap("C:\\Users\\Vardan\\GAmes_lines\\res\\background.png");
QPalette palette;
palette.setBrush(/*this->backgroundRole()*/QPalette::Background, QBrush(pixmap));
this->setPalette(palette);
}
MainWindow::MainWindow(std::string& str, QWidget *parent):
QWidget(parent)
{
}
double MainWindow::get_mouse_click_absolute_x_coordinate() const
{
return m_area_x0_coordinate;
}
double MainWindow::get_mouse_click_absolute_y_coordinate() const
{
return m_area_y0_coordinate;
}
void MainWindow::set_mouse_click_absolute_x_coordinate(double x)
{
m_area_x0_coordinate = x;
}
void MainWindow::set_mouse_click_absolute_y_coordinate(double y)
{
m_area_y0_coordinate = y;
}
void MainWindow::paintEvent(QPaintEvent *event)
{
if(m_status == false)
{
m_r->game_loop(this);
}
else
{
game_process::RECT temp = m_r->calculate_cell_rect(m_click_coords.first, m_click_coords.second);
int x = m_area_x0_coordinate + temp.x0;
int y = m_area_y0_coordinate + temp.y0;
std::pair<double, double> p;
/////////////////////////////////////////////////////////
start_timer();
//////////////////////////////////////////////////////////
for(int i = 2; i < 8; ++i)
{
char buf[sizeof(int)];
itoa(i, buf, 10);
std::string s(buf);
m_r->erase_frame(this, x, y);
while(m_timer_tick == false){}
p = m_r->draw_frame(this, m_click_coords.first, m_click_coords.second, s.c_str());
m_timer_tick = false;
}
end_timer();
m_status = false;
}
}
bool MainWindow::delay(int ms)
{
QTime dieTime = QTime::currentTime().addMSecs(ms);
while( QTime::currentTime() < dieTime )
return true;
}
void MainWindow::mousePressEvent (QMouseEvent* e)
{
qDebug() << "Local:" << e->pos().x();
qDebug() << "Local:" << e->pos().y();
std::pair<double, double> p = m_r->calculate_index_of_the_coordinates(e->pos().x(), e->pos().y(), m_width, m_height);
if(m_area_x0_coordinate <= e->pos().x() && m_area_y0_coordinate <= e->pos().y()
&& m_area_x0_coordinate + m_game_width >= e->pos().x() && m_area_y0_coordinate + m_game_height >= e->pos().y() )
{
m_status = true;
m_click_coords.first = p.first;
m_click_coords.second = p.second;
game_process::RECT coords = m_r->calculate_cell_rect(p.first, p.second);
Figure* f = m_r->detect_figure_by_index(p.first, p.second);
m_r->delete_cluster(this, f);
}
game_process::RECT r;
qDebug() << "Local:" << p.first;
qDebug() << "Local:" << p.second;
}
void MainWindow::timerEvent(QTimerEvent *event)
{
m_timer_tick = true;
}
void MainWindow::start_timer()
{
m_timer_id = startTimer(1000 / 30);
}
void MainWindow::end_timer()
{
killTimer(m_timer_id);
}
bool MainWindow::event(QEvent *e)
{
switch (e->type())
{
case QEvent::WindowActivate:
case QEvent::WindowDeactivate:
return true;
}
return QWidget::event(e);
}
I noticed that the timer does not start from paintEvent, and I need what he started with paintEvent. What to do?
I adjusted the code following your advice.
#include "mainwindow.h"
#include "game_process.h"
#include <QPixmap>
#include <QPainter>
#include <QPalette>
#include <QDesktopWidget>
#include <QResizeEvent>
#include <QDebug>
#include <QTimer>
#include <QTime>
#include <phonon/MediaObject>
#include <phonon/MediaSource>
#include <phonon/AudioOutput>
#include <utility>
#include <cassert>
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent)
{
QImage image("C:\\Users\\Vardan\\GAmes_lines\\res\\back_3.png");
m_width = 1000;
m_height = 800;
m_game_width = image.width();
m_game_height = image.height();
setFixedSize(m_width, m_height);
m_click_coords.first = 0;
m_click_coords.second = 0;
m_next_cell = 0;
m_frame_count = 2;
m_timer_tick = false;
m_timer_id = 0;
m_matrix_size = 0;
m_timer_flag = false;
setWindowFlags( Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
m_area_x0_coordinate = (this->width() - image.width())/2;
m_area_y0_coordinate = (this->height() - image.height())/2;
m_r = new game_process(m_area_x0_coordinate, m_area_y0_coordinate, image.width()/*+30*/, image.height()/*+30*/, 57);
m_status = false;
Phonon::MediaObject *mediaobject = new Phonon::MediaObject;
QString filename("C://Users//Vardan//GAmes_lines//music//Casino Ambiance Music.wav");
mediaobject->setCurrentSource(filename);
Phonon::AudioOutput *audio = new Phonon::AudioOutput;
Phonon::createPath(mediaobject,audio);
mediaobject->play();
QPixmap pixmap("C:\\Users\\Vardan\\GAmes_lines\\res\\background.png");
QPalette palette;
palette.setBrush(/*this->backgroundRole()*/QPalette::Background, QBrush(pixmap));
this->setPalette(palette);
}
MainWindow::~MainWindow()
{
}
MainWindow::MainWindow(std::string& str, QWidget *parent):
QWidget(parent)
{
}
double MainWindow::get_mouse_click_absolute_x_coordinate() const
{
return m_area_x0_coordinate;
}
double MainWindow::get_mouse_click_absolute_y_coordinate() const
{
return m_area_y0_coordinate;
}
void MainWindow::set_mouse_click_absolute_x_coordinate(double x)
{
m_area_x0_coordinate = x;
}
void MainWindow::set_mouse_click_absolute_y_coordinate(double y)
{
m_area_y0_coordinate = y;
}
void MainWindow::paintEvent(QPaintEvent *event)
{
static int ind = 0;
if(m_status == false && m_timer_tick != true)
{
m_r->game_loop(this);
}
else
{
std::pair<double, double> p;
int x = 0;
int y = 0;
static int s = m_r->get_close_map_size();
static std::vector<std::pair<int, int> > v = m_r->get_close_map_indexes();
if(m_frame_count >= 7)
{
m_frame_count = 2;
++m_next_cell;
if(m_next_cell <= v.size())
{
game_process::RECT temp = m_r->calculate_cell_rect(v[m_next_cell].second, v[m_next_cell].first);
x = m_area_x0_coordinate + temp.x0;
y = m_area_y0_coordinate + temp.y0;
m_x = x;
m_y = y;
}
}
if(m_next_cell == 0)
{
game_process::RECT temp = m_r->calculate_cell_rect(v[m_next_cell].second, v[m_next_cell].first);
x = m_area_x0_coordinate + temp.x0;
y = m_area_y0_coordinate + temp.y0;
m_x = x;
m_y = y;
}
if(m_frame_count < 7 && m_next_cell < v.size())
{
char buf[sizeof(int)];
itoa(m_frame_count, buf, 10);
std::string s(buf);
m_r->erase_frame(this, x, y);
p = m_r->draw_frame(this, v[m_next_cell].second, v[m_next_cell].first, s.c_str());
m_timer_tick = false;
c = true;
}
if(c == false && m_next_cell > v.size() - 1)
{
end_timer();
qDebug()<<"m_x = " << m_x;
qDebug()<<"m_y = " << m_y;
qDebug()<<"m_frame_count + 1 = " << m_frame_count + 1;
qDebug()<<"v.size() = " << v.size();
m_r->repaint_cells(this);
}
m_status = false;
}
}
void MainWindow::mousePressEvent (QMouseEvent* e)
{
qDebug() << "Local:" << e->pos().x();
qDebug() << "Local:" << e->pos().y();
std::pair<double, double> p = m_r->calculate_index_of_the_coordinates(e->pos().x(), e->pos().y(), m_width, m_height);
if(m_area_x0_coordinate <= e->pos().x() && m_area_y0_coordinate <= e->pos().y()
&& m_area_x0_coordinate + m_game_width >= e->pos().x() && m_area_y0_coordinate + m_game_height >= e->pos().y() )
{
start_timer();
m_status = true;
m_click_coords.first = p.first;
m_click_coords.second = p.second;
game_process::RECT coords = m_r->calculate_cell_rect(p.first, p.second);
Figure* f = m_r->detect_figure_by_index(p.first, p.second);
m_r->delete_cluster(this, f);
//this->update(m_area_x0_coordinate + coords.x0, m_area_y0_coordinate + coords.y0, 57, 57);
}
game_process::RECT r;
qDebug() << "Local:" << p.first;
qDebug() << "Local:" << p.second;
}
void MainWindow::timerEvent(QTimerEvent *event)
{
if(event->timerId() == m_timer_id)
{
m_timer_tick = true;
++m_frame_count;
if(m_x >=0 && m_y >=0)
{
qDebug()<<"m_x "<<m_x <<"m_y "<<m_y<<"time |||||| Passed";
this->update(m_x, m_y, 60, 60);
}
}
else
{
QWidget::timerEvent(event);
}
}
void MainWindow::start_timer()
{
m_timer_id = startTimer(50);
}
void MainWindow::end_timer()
{
killTimer(m_timer_id);
}
bool MainWindow::event(QEvent *e)
{
switch (e->type())
{
case QEvent::WindowActivate:
case QEvent::WindowDeactivate:
return true;
}
return QWidget::event(e);
}
Here's the code repaint_cells()
void game_process::repaint_cells(MainWindow* m)
{
Figure* f = 0;
for(int i = 0; i < 8; ++i)
{
for(int j = 0; j < 8; ++j)
{
if(m_close_list[j][i] == -1)
{
f = create_new_figure(j, i);
m_figures.push_back(f);
assert(f != 0);
draw_figure(m, f, i, j);
m_close_list[j][i] = 0;
}
}
}
}
enter link description here
For two days I can not understand why only one ball is drawn. Тhe remaining balls are not drawn.
You have two main approaches:
Simply define another slot with no parameters that will call game_process::render_cell(), then connect to the new slot.
If you're using Qt 5, use a lambda. See here for examples. It would look something like this: connect(timer, &QTimer::timeout, [=](){/*call the function here*/});
I recommend #2.
I see from your code snippet that you are passing a pointer to MainWindow to your render_cell() function, which I assume is some kind of widget or class derived from QObject.
In that case you could override the timerEvent(), which is defined for each QObject class and implement your game loop here. This way the parameters of your render_cell() could be be member variables of MainWindow, or your entire game_process class could be embedded in MainWindow.
Also, I think this approach is a little faster than using signals, which might be important for code that has to render something 30-60 times per second and update a bunch of other things.
For documentation see http://qt-project.org/doc/qt-4.8/qobject.html#timerEvent
In pseudo code, you could implement your game like this:
class MainWindow : public QWidget
{
private:
game_process *game;
int timer_id;
public:
MainWindow(void)
: QWidget(0),
game(0),
timer_id(0)
{
game = new game_process;
}
void startGame(void)
{
timer_id = startTimer(1000 / 30); // 30 fps
}
void endGame(void)
{
killTimer(timer_id);
}
protected:
virtual void timerEvent(QTimerEvent *event)
{
// update AI
// update network
// render game
game->render_cell(/* params */);
}
};
i am using q3Table.
i want to expand the column width to max item width by double click the edge of the header
while trying to connect to h3Header::sectionHandleDoubleClicked
i found in Q3Table code that it override the header double click event and not emitting the signal.
class Q_COMPAT_EXPORT Q3TableHeader : public Q3Header
{
void mouseDoubleClickEvent(QMouseEvent *e);
...
void Q3TableHeader::mouseDoubleClickEvent(QMouseEvent *e)
{
if (e->button() != LeftButton)
return;
if (isResizing) {
int p = real_pos(e->pos(), orientation()) + offset();
int section = sectionAt(p);
if (section == -1)
return;
section--;
if (p >= sectionPos(count() - 1) + sectionSize(count() - 1))
++section;
while (sectionSize(section) == 0)
section--;
if (section < 0)
return;
int oldSize = sectionSize(section);
if (orientation() == Horizontal) {
table->adjustColumn(section);
int newSize = sectionSize(section);
if (oldSize != newSize)
emit sizeChange(section, oldSize, newSize);
for (int i = 0; i < table->numCols(); ++i) {
if (table->isColumnSelected(i) && sectionSize(i) != 0)
table->adjustColumn(i);
}
} else {
table->adjustRow(section);
int newSize = sectionSize(section);
if (oldSize != newSize)
emit sizeChange(section, oldSize, newSize);
for (int i = 0; i < table->numRows(); ++i) {
if (table->isRowSelected(i) && sectionSize(i) != 0)
table->adjustRow(i);
}
}
}
}
as in the original q3Header a signal is emitted.
void Q3Header::mouseDoubleClickEvent(QMouseEvent *e)
{
int p = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();
p += offset();
if(reverse())
p = d->lastPos - p;
int header = handleAt(p);
if (header >= 0)
emit sectionHandleDoubleClicked(header);
}
how can i get the same effect as sectionHandleDoubleClicked?
or how can i achieve this effect?