Qt/C++ RTE when asking for selected indexes qtableview - c++

So for about a week i have been looking for solution of my problem. I have prepared my own model (after QAbstractTableModel) and it is displayed at default qTableView. I added to main menu an option, it is editiog an item:
void Window::EditPerson()
{
console->alert( "Choosing person" );
//console->alert( /*(QString)"Chosen person " +*/ QString::number( mainWidget->selectionModel()->selectedIndexes().size() ) );
if( mainWidget->selectionModel()->selectedRows().size() <1 )
return;
//console->alert( /*(QString)"Chosen person " +*/ QString::number( mainWidget->selectionModel()->selectedIndexes().size() ) );
//Person x = family->GetPerson( mainWidget->selectionModel()->selectedIndexes().value( 0 ).row() );
//EditPersonDialog( x );
}
Rapidly after calling this function (which is also the slot) in case there is selected any item i get RTE.
Thanks in advance for any help.

You should null-check the return value of selectedRows(). Although the documentation doesn't say, I think it might be NULL if there is no selection (which I assume you want to check in the condition).

Related

QT ComboBox ItemData from Database

I have the following code which links a QT QComboBox to my sqlite database and it works great.
However in my database I have the Category and Item table linked with a foreign key.
So when I pull info from the QComboBox I need to get the Category_ID not the name which is listed in the box.
How would I go about setting the QComboBox ItemData to the Category_ID field with a model or better yet use the model to set the QComboBox ItemData as my Category Object?
Thanks,
void MainWindow::populatCat()
{
QSqlQueryModel *model = new QSqlQueryModel();
QString sql;
sql = "select Category_Name From Category ORDER BY Category_Name ASC;";
QSqlQuery* query = new QSqlQuery(db);
query->prepare(sql);
if(!query->exec()){
qDebug () << "Query Erorr: " << query->lastError();
}else{
qDebug () << "Query Successful: " << query->lastQuery();
}
model->setQuery(*query);
ui->cboCat->setModel(model);
}
Okay, I'll present an answer now. :)
QComboBox* myBox = new QComboBox();
connect( myBox, SIGNAL( indexChanged( int ) ), this, SLOT( handleIndexChange( int ) ) );
void myObject::handleIndexChange( int /*index*/ ) {
// We actually don't need the index
QComboBox* box = qobject_cast<QComboBox*>( sender() );
if ( box ) {
QVariant data = box->currentData(); // do whatever w/ data... sounds like call toInt() in your case.
}
}
The essence of all three of my approaches is that you have to do something extra to get data() which corresponds to the current item after a change. It would be nice if it emitted a signal taking the underlying data as the argument, but that could get expensive.

check if the name already exists in QTableWidget

I have a problem.
I have 2 QTextEdit fields : value & name.
When I push the button i create QTableWidgetItems with the value from "value" and "name".
But now I will check if the name alredy exists.
But I don't know, with " findItems " ? with contain's ?
Tabelle extends from QWidget in the header.
I'am an c++/ QT Beginner and have no idea as I do that such.
PS: I'am speaking Germany, so you can answer in Germany, my English isn't very good ;D
Thank you :)
void Tabelle::pushButtonClicked() :
strname = ( txtname ->text ());
strvalue = ( txtvalue ->text ());
The textfields to Strings.
Put the vlaue in Items:
QTableWidgetItem * valueitem = new QTableWidgetItem(0);
valueitem->setText(strvalue);
QTableWidgetItem * nameitem = new QTableWidgetItem(0);
nameitem->setText(strname);
New row :
if ( cou >coucount )
{table->insertRow(table->rowCount());}
table->setItem( cou,1, valueitem );
table->setItem( cou, 0, nameitem); cou++
You can use QList QTableWidget::findItems(const QString & text, Qt::MatchFlags flags) const.
As the doc says:
Finds items that matches the text using the given flags.
Try the following code:
QList<QTableWidgetItem *> ItemList = Table->findItems("TestName", Qt::MatchExactly);
cout<< "Count:" << ItemList.count() << endl;

Qt debugger does different than simple running

void MainWindow::edit()
{
//Check if item is selected, if not return
const int row = list->currentRow();
if( row == -1 )
return;
EditWindow w( this, currentCategory() );
switch( currentCategory() )
{
case cApp:
{
App old = appList.at( row );
w.setApp( old );
if( w.exec() == QDialog::Rejected )
return;
if( old == w.app() ) return;
else old = w.app();
if( dm->updateApp( old ) ){
appList.replace( row, old );
list->item(row)->setText( old.name() );
}
break;
}
case cFilm:
{
Film old = filmList.at( row );
w.setFilm( old );
if( w.exec() == QDialog::Rejected )
return;
if( old == w.film() ) return;
else old = w.film();
if( dm->updateFilm( old ) ){
filmList.replace( row, old );
list->item(row)->setText( old.name() );
}
break;
}
case cSong:
{
Song old = songList.at( row );
w.setSong( old );
if( w.exec() == QDialog::Rejected )
return;
if( old == w.song() ) return;
else old = w.song();
if( dm->updateSong(old) ){
songList.replace( row, old );
list->item(row)->setText( old.name() );
}
break;
}
}
displayItem(row);
}
This code checks which category we have at the moment. Then it edits an app, a movie or a song (depends on the category). Then when I change some informations it writes these changes to the database and the global QLists, change the name in the QListWidget and displays the current item's information in a few labels (it's the last function).
As you can see it's the same code except that the QLists are different. Movies and songs work perfectly. I can change every detail and it automatically updates the name in the list.
But when I change the name of an app and click ok it doesn't change the name in the list and doesn't change the apps information in the QList.
However, when I go through it with a debugger and click on every single step the list changes the name and the information.
So basically what I am trying to ask is why does this code above work when using the debugger going through each step but not when just running it?
I guess that what you call "simple running" is actually using your IDE in "build to run" mode and you are in fact comparing a debug build with an optimised release build. The debugger properly initialises all memory to zero which doesn't happen in the release build.
Regardless of what you are doing, this behaviour is indicative of illegal memory access.
From your code everytime you use at() you are at risk of going out of bounds and I guess that is what is happening. You should check all instances of at() and also list->item(row) are not going out of bounds.
Furthermore using list is at risk of being confused with std::list, therefore this variable should be renamed.

Qt: Print raw text

I need to output a ZPL script to a Zebra printer in a Qt application.
The printer is on a smb share network configured as raw printer in the client computer.
Everything goes fine if I call cupsPrintFile( "printer_name", "./tmp_print_file.zpl", "", 0, NULL ) from a C++ test program.
If I use QTextDocument::print() using the same text in "./tmp_print_file.zpl" as document, nothing gets printed.
I sniffed the network and found that the data being sent to the printer server is not raw data, but, a postscript!
Is there any way to get the data sent to the printer with no modification at all?
Let me be clear that I don't want to render a text, but just send the label script, that is ready to print, directly to the printer, that understands the ZPL protocol.
Thanks for all.
EDIT:
As #Martin said, I tried:
printer.setOutputFormat( QPrinter::NativeFormat );
QTextDocument *doc = new QTextDocument( QString( label ), this );
doc->print( &printer );
but it didn't work.
Before I start, must thank Dave. His suggestion to bypass the temporary file while printing with CUPs works fine.
Now, my conclusion: There is no easy way to print raw data using Qt only.
Maybe creating custom QPainter or going down to the bits of QPrinter could give a solution, but it would take me too much time.
The final solution is simply use CUPs API inside my Qt application. Unfortunatelly, it is not portable.
Here is a snippet:
#include <cups/cups.h>
//...
int print_label( const char *text, const char *printer_name, const char *job_name )
{
int jobId = 0;
jobId = cupsCreateJob( CUPS_HTTP_DEFAULT, printer_name, job_name, 0, NULL );
if ( jobId > 0 )
{
qDebug( ) << "Printing job #" << jobId << " (\"" << job_name << "\").";
const char* format = CUPS_FORMAT_TEXT; // CUPS_FORMAT_POSTSCRIPT;
cupsStartDocument( CUPS_HTTP_DEFAULT, printer_name, jobId, text, format, true );
cupsWriteRequestData( CUPS_HTTP_DEFAULT, text, strlen( text ) );
cupsFinishDocument( CUPS_HTTP_DEFAULT, printer_name );
}
return jobId;
}
//...
// Now, inside any Qt function (may be a slot):
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog( &printer, this );
dialog->setWindowTitle( tr( "Zebra label" ) );
if ( dialog->exec( ) != QDialog::Accepted )
return;
// This is the sample label. Can be anything.
const char label[] =
"^XA~TA000~JSN^LT0^MNW^MTD^PON^PMN^LH0,0^JMA^PR4,4^MD0^JUS^LRN^CI0^XZ\n"
"^XA\n"
"^MMT\n"
"^LL0600\n"
"^PW900\n"
"^LS0\n"
"^BY2,3,54^FT24,109^BCN,,Y,N\n"
"^FD>;43210000>773>0000^FS\n"
"^PQ1,0,1,Y^XZ\n";
// Informative only.
ui->txtLabelScript->setPlainText( label );
// Call the printing function.
if ( print_label( label, printer.printerName( ).toAscii( ), "Zebra_Label" ) == 0 )
qDebug( ) << "CUPS Error: " << ippErrorString( cupsLastError( ) );
And it's done.
Don't forget to link libcups (-lcups).
I still hope any buddy to add another solution prooving that Qt-only is possible. Meanwhile, it is enough.
Thanks everybody.
Could you just do exactly what you did in your test program:
Create a temporary file (QTemporaryFile).
Send the contents to the file.
Call your cupsPrintFile method.
Or there is probably a way with the CUPS API to bypass the temporary file. Disclaimer: I have absolutely no experience with the CUPS API; this is just based on a cursory look at some online documentation. Looks like perhaps the following sequence:
cupsCreateJob > cupsStartDocument > cupsWriteRequestData > cupsFinishDocument
If that works, you just need to convert your QString to the correct byte encoding.
Thanks for fljx's code, it is very useful for me.
I changed a litte for sending raw text to zebra printer .
const char* format = CUPS_FORMAT_RAW;
Take a look at QPrinter(),
QTextDocument is designed to render formatted text.

Icon click on Qt QTreeWidget

I have a treewidget in my Qt form. It shows a tree of files, showing a icon representing something about them, and their name.
I entered these using treeItem->setIcon(0, *icon), and treeItem->setText(0, text) .
The reason I entered both values to the same column (0), is because otherwise the icons would not stay next to the text, rather always stick to the left, even when the text was indented to the right (because it's a child of another item).
The problem is, now I can't tell if the user clicked on the icon or on the text itself, and I need to deal with these separately.
So, is there anyway to get more info than just the treeitem and column when an object in a treewidget is clicked,
or is there any way to put them on seperate columns and still have the normal behavior icons and text should have?
Thanks.
I don't think there is a straight forward way to get more info, if you are simply using the clicked() or itemClicked() signals. You probably have to create a custom class that inherits QTreeWidget, and reimplement one of the virtual mouse-event functions.
mouseMoveEvent ( QMouseEvent * )
mousePressEvent ( QMouseEvent * )
mouseReleaseEvent ( QMouseEvent * )
This is not something I would recommend, unless you really know what you are doing, and really need to do it.
However, I can't remember seeing a list widget anywhere, where clicking an icon is handled differently from clicking the text in the same column. So if you are looking for "the normal behavior icons and text should have", you probably should look for another solution.
I found the following solution for this problem:
void MyTreeWidget::mousePressEvent( QMouseEvent* aEvent )
{
QTreeWidget::mousePressEvent( aEvent );
const QPoint clickedPosition = aEvent->pos();
const QRect itemRectangle = visualItemRect( itemAt( clickedPosition ) );
const int iconOffset = itemRectangle.height() - iconSize().height();
QRect iconRectangle;
iconRectangle.setTopLeft( itemRectangle.topLeft() + QPoint( iconOffset, iconOffset ) );
iconRectangle.setWidth( iconSize().width() );
iconRectangle.setHeight( iconSize().height() );
if ( iconRectangle.contains( clickedPosition ) )
{
qDebug() << "ICON clicked";
// Emit an icon clicked SIGNAL.
}
}