1

I have a small problem trying to propoerly parse a .txt files and show its content on a QTableView. Specifically how to extract the headers of the file and show them into a QTableView.

The .txt file is composed of a first row which carries the headers, and all the other rows, which are data.

I can successfully upload the .txt file on a QTableView but for some reasons, the whole file appears under one gigantic column instead of properly parsing all the different headers and put them on the QTableView.

Below the example .txt file I am uploading on the QTableView - specifically the headers:

tax_id  Org_name    GeneID  CurrentID   Status  Symbol  Aliases description other_designations  map_location    chromosome  genomic_nucleotide_accession.version    start_position_on_the_genomic_accession end_position_on_the_genomic_accession   orientation exon_count  OMIM    

Below the rows of some exmaple data:

1041930 Methanocella conradii HZ254 11971032    0   live    mRNA    MTC_RS04550, Mtc_0908   coenzyme-B sulfoethylthiotransferase subunit alpha  coenzyme-B sulfoethylthiotransferase subunit alpha          NC_017034.1 886220  887887  plus    0       
79929   Methanothermobacter marburgensis str. Marburg   9705221 0   live    mRNA    MTBMA_RS07375, MTBMA_c15120 coenzyme-B sulfoethylthiotransferase subunit alpha  coenzyme-B sulfoethylthiotransferase subunit alpha          NC_014408.1 1393293 1394954 minus   0       
523846  Methanothermus fervidus DSM 2088    9962464 0   live    mRNA    MFER_RS03735, Mfer_0734 coenzyme-B sulfoethylthiotransferase subunit alpha  coenzyme-B sulfoethylthiotransferase subunit alpha          NC_014658.1 713917  715581  plus    0       

EDIT

Below the Excel file of the same .txt I posted for clarity in the visualization. this is the expected output on the QTableView after parsing the .txt file and its headers

expected table

This is the wrong output that is currently happening which puts everything under a gigantic column.

tab

Currenlty this upload the .txt file into the QTableView. However it is not divided per header, but it is just a gigantic column and I don't know why despite I split the strings:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    model = new QStandardItemModel(this);

    ui->tableView->setModel(model);
    ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

    setWindowTitle("Viewer Example");
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_loadTXTBtn_clicked()
{
    auto filename = QFileDialog::getOpenFileName(this, "Open", QDir::rootPath(), "txt file (*.txt)");
    if(filename.isEmpty()) {
        return;
    }
    QFile file(filename);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return;
    }
    QTextStream xin(&file);
    int ix = 0;
    while (!xin.atEnd()) {
        model->setRowCount(ix);
        auto line = xin.readLine();
        auto values = line.split("   ");
        const int colCount = values.size();
        model->setColumnCount(colCount);
        for(int jx = 0; jx < colCount; ++jx) {
            setValueAt(ix, jx, values.at(jx));
        }
        ++ix;
        ui->pathLineEdit->setText(filename);
    }
    file.close();
}

void MainWindow::setValueAt(int ix, int jx, const QString &value)
{
    if (!model->item(ix, jx)) {
        model->setItem(ix, jx, new QStandardItem(value));
    } else {
        model->item(ix, jx)->setText(value);
    }
}

In doing research on how to solve the problem I found this post useful and also this one. In particular the last post was very useful for understanding how to parse through the headers but I still was not able to properly understand how to extract those and show them into a QTableView. Please any pointers on how to solve would be great!

EsoMars
  • 337
  • 3
  • 14
  • I would advise you to shrink your problem to an MRE (minimal reproducible example). People check the size of your code and bail out. – Something Something Aug 30 '22 at 04:48
  • @HenriqueBucher, thanks for the comment. It is already a minimal verifiable example. Create a `QWidget` Application on Qt5 and copy/past my code. It will work no problem. Unofortunately I don;t know how to properly loop through the first row of the `.txt` and make that as a headers of the `QTableView`. – EsoMars Aug 30 '22 at 17:47
  • I hope my question is clear. I am more than happy to edit it if you think that it is not precise in some specific aspects :) – EsoMars Aug 30 '22 at 17:48
  • Your `.txt` file is not well formed, some values are separated by one space, others by multiple spaces. What is the expected table for the example? can you make some excel sheet or table and add photo of your desired output? – Ali-Ibrahim Aug 30 '22 at 18:56
  • @EsoMars Just saying that your code is still "scary" to look. That was my first thought when I first saw it. You can take this advice for whats worth but the lack of responses and the age of the question is telling. – Something Something Aug 30 '22 at 22:11
  • @C137, thanks for the comments. Yes I know, in fact it is the file that I receive as output after working on another software. That `.txt` is the answer I receive from another software. Absolutely, I will make an `excel` example of what I am looking for. Thanks for the suggestion! :) Will post it shortly! – EsoMars Aug 31 '22 at 16:02
  • @C137 I just edited the question adding the Excel screenshot of what is the expected output vs current output. – EsoMars Aug 31 '22 at 16:25
  • @HenriqueBucher, thaks for your comments too. I edted the question and left only the minimal information as you suggested erasing the extra. I made a small edit assuggested by C137 to make the question clearer. I appreciate everyone's comment! I am still new in SO community! So thanks for helping out to make the question better! :) – EsoMars Aug 31 '22 at 16:27
  • Also as an additional clarification to @C137, the file I am trying to parse may have some empty columns (I showed it there on purpose). But that is due to the initial software who process the data. I can't help that. I just have to load the `.txt` file on the `QTableView` and make sure that all the data are aligned with the column headers. I hope that clarifies even more any doubts you might have! :) – EsoMars Aug 31 '22 at 16:30
  • Thank you for your effort to clarify everything. I dont see errors in your code, the only thing that is not correct is the `txt` file format, even as a human I couldnt understand it! My suggestion is use `csv` insteade, as you have rules how to parse the file. Good luck with that. – Ali-Ibrahim Aug 31 '22 at 16:35
  • I tried it too. I changed the extension of the `.txt` into a `.csv`. But I still see everything under a gigantic table instead of properly divided by columns. I just have a huge column. And I don't know how to solve that... – EsoMars Aug 31 '22 at 16:38

1 Answers1

1

Assuming you have your data in cvs file with ; separator instead of .txt The code will be like this:

namespace constants
{
const QStringList HEADERS = {
    "tax_id", "Org_name", "GeneID", "CurrentID", "Status",
    "Symbol", "Aliases", "description", "other_designations",
    "map_location", "chromosome", "genomic_nucleotide_accession.version",
    "start_position_on_the_genomic_accession", "end_position_on_the_genomic_accession",
    "orientation", "exon_count", "OMIM"};
}
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    model = new QStandardItemModel(this);
    ui->tableView->setModel(model);
    model->setHorizontalHeaderLabels(constants::HEADERS);
    model->setColumnCount(constants::HEADERS.length());
    ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);
    setWindowTitle("Viewer Example");
    OpenFile();
}
void MainWindow::OpenFile()
{
    auto filename = QFileDialog::getOpenFileName(this, "Open", QDir::rootPath(), "txt file (*.csv)");
    if(filename.isEmpty()) {
        return;
    }
    QFile file(filename);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return;
    }
    QTextStream xin(&file);
    int row = 0;
    while (!xin.atEnd()) {
        auto line = xin.readLine();
        auto values = line.split(";");
        const int colCount = model->columnCount();
        for(int col = 0; col < colCount; ++col)
        {
            setValueAt(row, col, values.at(col));
        }
        row++;
        ui->pathLineEdit->setText(filename);
    }
    file.close();
}

void MainWindow::setValueAt(int ix, int jx, const QString &value)
{
    if (!model->item(ix, jx)) {
        model->setItem(ix, jx, new QStandardItem(value));
    } else {
        model->item(ix, jx)->setText(value);
    }
}

Your data.csv example file will be like this:

1041930;Methanocella conradii HZ254;11971032;0;live;mRNA;MTC_RS04550, Mtc_0908;coenzyme-B sulfoethylthiotransferase subunit alpha;coenzyme-B sulfoethylthiotransferase subunit alpha;;;NC_017034.1;886220;887887;plus;0;;
79929;Methanothermobacter marburgensis str. Marburg;9705221;0;live;mRNA;MTBMA_RS07375, MTBMA_c15120;coenzyme-B sulfoethylthiotransferase subunit alpha;coenzyme-B sulfoethylthiotransferase subunit alpha;;;NC_014408.1;1393293;1394954;minus;0;;

I don't think there is a clean way to achieve what you want with the way your txt file is formatted.

Ali-Ibrahim
  • 835
  • 1
  • 6
  • 16
  • That is fantastic C137! This is much more than I expected. And yes, given the very strange file, I think that there is not a super clean way to do that. Or at least nothing comes to my mind! Thanks so much so your time and for giving me a hand! :) – EsoMars Aug 31 '22 at 19:25