I'm very new to QT and I have an application which has a QTableWidget in it and I want to add save and load option to my application. the question is how to save and load data in QTableWidget. I found this page:http://doc.qt.io/qt-5/qtwidgets-tutorials-addressbook-part6-example.html#defining-the-addressbook-class but it wasn't useful:I tried a code like this to save:
void training::on_pushButton_3_clicked()
{
QVector<QTableWidgetItem*> outvector;
for(int i = 0;i<ui->tableWidget->rowCount();i++)
for(int ii=0;i<ui->tableWidget->columnCount();ii++)
outvector.append(ui->tableWidget->item(i,ii));
QString path = QFileDialog::getSaveFileName(this,QString("Save file path"),"",QString("table (*.tbl);;All Files (*)"));
if(path.isEmpty())
return;
else{
QFile file(path);
if(!file.open(QIODevice::WriteOnly)){
QMessageBox::information(this,"Error",file.errorString());
return;
}
else{
QDataStream out(&file);
out.setVersion(QDataStream::Qt_5_11);
out<<outvector;
}
}
}
Is this right?! If it works how to load the information again; if not how to save and load data in tablewidget?
Any help would be appreciated.
Make this correction to your code:
...
for(int ii=0;ii<ui->tableWidget->columnCount();ii++)
...
For this (save and load data in QTableWidget) look at Serialization with Qt, So you need to consider what exactly you want to Save/load (serialize). since QVector is serializable, I think your code won't complain, but indeed it won't store your actual data, QTableWidgetItems, because that data type is not in list of serializable types - try to directly save an individual item and you will know what errors will come. Moreover, serializing compound types (vector of table items) may not be the right approach even if both types are supported.
In order to solve your issue, you need to serialize whatever data you store in your QTableWidget items, for example read text from item and store ...etc.
Thanks it's fixed up using
item.write(outstream);
I saved everyitem using write function then with same order I used read function item.read(instream) to load it again.
Related
I am currently writing an application in Qt, which is basically a warehouse. An application reads CSV, enables user to process it and enables to show picture of each good. I tried displaying picture using QLabel and Pixmap, however nothing happens even though the file is in the same folder and the name provided is exactly as it should be. Is it the resources issue or my code fails somehow? Is there any possibility to display the image without adding it to resources in order to avoid adding many photos manually?
void ImageViewer::viewImage(QString imgName)
{
QString pathWithName = imgName;
pathWithName.append(".jpg");
ui->label->setPixmap( QPixmap(pathWithName) );
ui->label->show();
update();
}
Sorry for any mistakes in post creation or code displaying here- it's my first post.
Edit:
I am adding code from MainWindow (called CsvReader in my project) to how I'm invoking the method viewImage:
void CsvReader::on_imgView_clicked()
{
ImageViewer* img = new ImageViewer(this);
img->setModal(true);
img->exec();
QModelIndex List selInd ui->tableView->selectionModel()->selectedIndexes();
QString id = model->item(selInd.first().row(), 0)->text();
img->viewImage(id);
}
Edit 2:
Solved. Had to change path using QDir:
QDir* directory = new QDir("/home/kokos/Magazyn/photos");
QFileInfo checkFile(*directory, pathWithName);
Thanks in advance,
Kokos
Confirm your file's location and existence first. Add this;
QFileInfo checkFile(pathWithName);
if (checkFile.exists() && checkFile.isFile()) {
// your code
}
I'm having issues with formulating the question but this is what I want to do with my application.
A user can select one or multiple image-files (.ppm), and they are displayed in some sort of legend, with their filename underneath. The information of these images is stored in a structure. (This structure contains the image path, name, and other info).
Now I want to give the user the chance to change the name of the selected images, and uses this name in the rest of the application. So I would have to change the name in the structure.
I could do this by adding textfields in the legend, where users can type the desired name, but how can I get the input from this textfield if I don't know which one is alterred?
If the user selects 6 images, I need 6 new textfields in the legend, but how can I address the correct one?
struct[2].name = input2.getText();
I also thought about doing it with some sort of wizard, with 6 pages where the names can be changed, but I don't know how I can adress the correct textfield.
Any help would be welcome, thanks!!
If you want to allow users to rename multiple files at one time, you may want to create a wizard. In the wizard you could display each picture they selected (one at a time) and allow them to rename each picture (one at a time). Otherwise it will be confusing to the user and harder for you to manage.
When generating the wizard, I would use the information structure to associate the picture with the textfield.
Qt, signals and slots are your friend here.
When you setup the textfields for the name, assuming you use something like a QLineEdit object, connect to a relevant signal, such as editingFinished(). Make the connection to the slot of the Object that stores the structure. The receiving slot then updates the appropriate information.
So, assuming your struct is in an object derived from QObject, you can do something like this: -
struct DataStruct // the struct storing the underlying data
{
QString name;
QLineEdit* linkedEditWidget; // widget for user to change text
};
class MainObject : public QObject
{
Q_OBJECT // required for signals and slots
public slots:
void UpdateText();
private:
const int NUM_STRUCTS = 10; // initialisation in C++ 11
DataStruct myStructs[NUM_STRUCTS]; // a number of structs
};
When you initialize the array of structs and the LineEdit widgets, store a pointer to the matching LineEdit widget in each myStruct and connect the widgets' editingFinished signals to the MainObject updateText() slot. It would be a good idea to use weak smart pointers here, but I'll use a standard pointer, to keep things simple.
When you receive notification that the text has changed, you'll need to match up the caller with the LineEdit* in the struct. Note that QObject::sender() will return the pointer to the object that sent the message: -
void MainObject::UpdateText()
{
QObject* theSendingWidget = sender();
for(int i=0; i<NUM_STRUCTS; ++i) // assuming NUM_STRUCTS is already defined
{
if(myStructs[i].linkedEditWidget == theSendingWidget)
{
// update the name in the data struct
myStructs[i].name = (static_cast<QLineEdit*>(theSendingWidget))->text();
return; // our work is done.
}
}
}
Finally, you'd probably make life easier for yourself by storing the data in Qt model objects, rather than using a plain struct. I suggest reading up on Model / View programming and the MVC design pattern
I have a Monitoring program which runs another long process (can take days). The process generates huge amount of log information. This log information cant be stored in memory so I am redirecting it into log file. The problem is than Monitoring program need to display this log. I cant use a widget that requires storing entire text in memory. I need to have somting like
class TextView
{
void setModel(TextModel*)
}
class TextModel
{
int pageCount();
QString page(int i);
Q_SIGNALS:
void pageCountChanged(int cnt)
};
Implementation of TextModel will load page in memory per request.
Of courese I can implement Text Viewer widget from the scratch, but I have no enough time to do that. Any sugestions?
You can use QListView and derive your model from QAbstractListModel. You need to define rowCount and data methods in your model.
I know this could be a really small thing i am missing here, but I have spent some good amout our hours trying to figure this out. I am from an Objective-C background and what I am trying to do is this:
I have a main.qml which is a navigationPane and it has 2 other external pages added to it as attached object. The two pages have grid list views. Now, There is a MyApp.cpp file that loads a Json file and populates the result in the main.qml file. I only display the relevalt items on this page at first. When the user taps on any item, I want to take them to page2.qml which has a grid list view as I mentioned above and populate it with dataModel passed from main.qml (which has all the data from MyApp.cpp). This has give me no joy at all! I need help. What can I do to make this work? Please I need help on this one...
I'm not sure if this is best practice or not, but the easiest method I found was to use the Qt global object.
Basically assign either your data or an object to the Qt object and then you can access it from any other page.
E.g.
In main.qml in onCreationCompleted or whatever function you receive your data in:
function getData(data) {
Qt.myVariable = data;
}
Then in your other page(s) you can access it. E.g. in Page2.qml:
Page {
onCreationComplete: {
myLabel.text = Qt.myVariable;
}
}
As I mentioned, this works for objects as well, so you can assign a navigation pane, a sheet, a page, etc. So things like "Qt.myNavPane.push(page)" becomes possible.
I encountered issues where I needed to use Qt for various purposes. Signals and slots are better practice I think, but are not always practical.
I have a QWebView, and it loads a certain page, the user logs in and goes about his business. This all works fine.
What I would like to do is have a second frame/pae open, that uses the logged in users session and all that jazz to load a reports page that it will render to an image file for display on a little USB screen.
Right now, I accomplish this with a completely different webView, which can't access protected pages, which is a bit of a security risk.
Here is some pseudo code for what I am thinking of:
webView->mainFrame->loadNormalUrl
secretFrame = webView->createSecretFrame
secretFrame->useSessionOf(webView->mainFrame)
secretFrame->loadReportUrl
secretFrame->doStuffThatAlreadyWorks
Any help, pointers, links would be super helpful! Thanks :)
Well,
This question didn't receive and answer, so I pattered off to the qtwebkit mailing list, and they were very helpful.
The essential thing is to subclass QNetworkCookieJar, the most important method being the loading from disk, which you call in your constructor.
QList<QNetworkCookie> cookies;
if (m_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&m_file);
QString txt = in.readAll();
QStringList lines = txt.split("\n");
foreach (QString c, lines) {
cookies.append(QNetworkCookie::parseCookies(c.toUtf8()));
}
m_file.close();
}
setAllCookies(cookies);
Of Course, you'll also need a writing function, like so:
QTextStream out(&m_file);
foreach (const QByteArray &cookie, m_rawCookies)
out << cookie + "\n";
m_file.close();
And your raw cookies like so:
QList<QNetworkCookie> cookies = allCookies();
m_rawCookies.clear();
foreach (const QNetworkCookie &cookie, cookies) {
m_rawCookies.append(cookie.toRawForm());
}
If you download the webkit source, you can take a look at the testbrowser code for a more complete example.
One way you could approach this is to not try to do it with QWebViews at all, but instead subclass QNetworkManager and hook its signals to snoop the QNetworkReplys that are sent back.
Otherwise in your second QWebView you could just set its content to the HTML you want to display and you might be able to enforce only grabbing data from the cache.