I am trying to create a progress bar for a file copy in Qt. This is as close as I could find, however I believe this doesn't work because according to the Qt class documentation:
Unlike other QIODevice implementations, such as QTcpSocket, QFile does
not emit the aboutToClose(), bytesWritten(), or readyRead() signals.
This implementation detail means that QFile is not suitable for
reading and writing certain types of files, such as device files on
Unix platforms.
How can I do something like this? I don't know how to implement my own signals.
Here is my code:
void Replicator::anotbaandbFile(QDir source, QDir target)
{
source.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
target.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
qDebug() << "Scanning: " << source.path();
QStringList sourceFileList = source.entryList();
QStringList targetFileList = target.entryList();
for (int aCount = 0; aCount < sourceFileList.count(); aCount++)
{
bool found = false;
for (int bCount = 0; bCount < targetFileList.count(); bCount++)
if (sourceFileList.at(aCount) == targetFileList.at(bCount))
found = true;
if (found == false)
{
sourceFile = new QFile(source.absolutePath()+"/"+sourceFileList.at(aCount));
targetFile = new QFile(target.absolutePath()+"/"+sourceFileList.at(aCount));
progressBar->setMinimum(0);
progressBar->setMaximum(sourceFile->size());
written = 0;
connect(sourceFile,SIGNAL(bytesWritten(qint64)),SLOT(onWrite(qint64)));
sourceFile->copy(targetFile->fileName());
//QFile::copy(source.absolutePath()+"/"+sourceFileList.at(aCount), target.absolutePath()+"/"+sourceFileList.at(aCount));
qDebug() << source.absolutePath()+"/"+sourceFileList.at(aCount) << " " << target.absolutePath()+"/"+sourceFileList.at(aCount);
}
}
}
and
void Replicator::onWrite(qint64 w)
{
written += w;
progressBar->setValue( written );
}
new code modified from above
if (found == false)
{
sourceFile = new QFile(source.absolutePath()+"/"+sourceFileList.at(aCount));
targetFile = new QFile(target.absolutePath()+"/"+sourceFileList.at(aCount));
progressBar->setMinimum(0);
progressBar->setMaximum(sourceFile->size());
QByteArray buffer;
for (int count = 0; !(buffer = sourceFile->read(1000000)).isEmpty(); count+=1000000)
{
targetFile->write(buffer);
progressBar->setValue(count);
}
//targetFile->write(buffer);
//QFile::copy(source.absolutePath()+"/"+sourceFileList.at(aCount), target.absolutePath()+"/"+sourceFileList.at(aCount));
qDebug() << "copying " << sourceFile->fileName() << " to " << targetFile->fileName();
}
You can simply copy large files by portions of fixed size, than count portions already copied and callculate of percentage of work by dividing it to overal count of portions.
int iWorkPercentage = (int)(((float)iPortionsProcessed / (float)iOveralPortions) * 100);
Related
Im working in code which can create coronal, saggital, and axial image from dicom file, but In the same time I dont need to display renderWindow to user, and this is my code:
int main(int argc, char* argv[])
{
// Verify input arguments
if ( argc != 2 )
{
std::cout << "Usage: " << argv[0]
<< " FolderName" << std::endl;
return EXIT_FAILURE;
}
std::string folder = argv[1];
//std::string folder = "C:\\VTK\\vtkdata-5.8.0\\Data\\DicomTestImages";
// Read all the DICOM files in the specified directory.
vtkSmartPointer<vtkDICOMImageReader> reader =
vtkSmartPointer<vtkDICOMImageReader>::New();
reader->SetDirectoryName(folder.c_str());
reader->Update();
// Visualize
vtkSmartPointer<vtkImageViewer2> imageViewer =
vtkSmartPointer<vtkImageViewer2>::New();
imageViewer->SetInputConnection(reader->GetOutputPort());
imageViewer->SetSlice(0);
imageViewer->Render();
for(int k = 0; k < 3; k++){
cout<< k << endl;
if(k == 0){
imageViewer->SetSliceOrientationToYZ();
}else if(k == 1){
imageViewer->SetSliceOrientationToXZ();
}else{
imageViewer->SetSliceOrientationToXY();
}
int _MinSlice = imageViewer->GetSliceMin();
int _MaxSlice = imageViewer->GetSliceMax();
// Screenshot
vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter =
vtkSmartPointer<vtkWindowToImageFilter>::New();
vtkSmartPointer<vtkPNGWriter> writer =
vtkSmartPointer<vtkPNGWriter>::New();
for (int i = _MinSlice; i < _MaxSlice; i++){
vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter =
vtkSmartPointer<vtkWindowToImageFilter>::New();
vtkSmartPointer<vtkPNGWriter> writer =
vtkSmartPointer<vtkPNGWriter>::New();
windowToImageFilter->SetInput(imageViewer->GetRenderWindow());
windowToImageFilter->ReadFrontBufferOff(); // read from the back buffer
windowToImageFilter->Update();
std::string filename = "img/" + std::to_string(k) + "/" + std::to_string(i) + ".png";
char *y = new char[filename.length() + 1];
std::strcpy(y, filename.c_str());
writer->SetFileName(y);
writer->SetInputConnection(windowToImageFilter->GetOutputPort());
writer->Write();
imageViewer->SetSlice(i);
imageViewer->Render();
}
}
return EXIT_SUCCESS;
}
my issue is when try imageViewer->SetRenderWindow(NULL); Or imageViewer->GetRenderWindow()->Delete(); its will remove renderWindow instance, and code will be break, so that how I can keep renderWindow work in background without display it to user?
Thanks
You can use SetShowWindow(bool) or ShowWindowOff(), these methods are inherited from vtkWindow. Doing so should not stop the rendering pipeline (you can probably still use windowToImageFilter) but tbh I did not test it. Let us know if it worked.
I can't find a related solution so i finally post here.
I have a very small program that uses the RTMidi library to map the controllers keys as hotkeys. Everything works fine in debug mode and releasing the app doesn't give me any errors either, but the RTMidiIn class isn't finding any Ports in the release version.
This is my code
MidiToMacro::MidiToMacro(QWidget *parent)
: QMainWindow(parent)
{
m_ui.setupUi(this);
RtMidiIn *midiin;
try
{
midiin = new RtMidiIn(RtMidi::WINDOWS_MM);
}
catch (RtMidiError &error) {
m_ui.uiLog->append("midiin initiation failed!");
error.printMessage();
exit(EXIT_FAILURE);
}
unsigned int nPorts = midiin->getPortCount();
QString inputCount = QString::number(nPorts);
m_ui.uiLog->append("There are " + inputCount + " MIDI input sources
available.");
std::string portName;
std::string akai = "Akai MPK49 2";
opened = 1000;
for (unsigned int i = 0; i < nPorts;++i)
{
try
{
portName = midiin->getPortName(i);
if (portName == akai)
{
midiin->openPort(i);
midiin->setCallback(&mycallback, this);
opened = i;
}
}
catch (RtMidiError &error)
{
//not printing an error
error.printMessage();
delete midiin;
}
QString portnumber = QString::number(i);
m_ui.uiLog->append(" Input Port #" + portnumber + ": " + QString::fromStdString(portName));
}
if (opened == 1000)
{
m_ui.uiLog->append("Error finding Akai Controller!");
}
Forgot to define WINDOWS_MM in the preprocessor definitions of release.
I try to support the program in Mac OS. The program must move one specific window of another program (the program must have more than 1 window open) to the specified monitor and expand it to the full screen. For Windows and Linux, this was implemented using a native API, but for MacOS it did not find an API to change Windows from its application. Could find a way to get the window ID but not change its state.
m_currentWindow->mac = 0;
CGWindowListOption option = kCGWindowListOptionAll;
CGWindowID id = 0;
CFArrayRef windows = CGWindowListCreate(option, id);
if(windows == nullptr)
{
qCCritical(actOp) << "windows is null";
return;
}
CFArrayRef desc = CGWindowListCreateDescriptionFromArray(windows);
if(desc == nullptr)
{
qCCritical(actOp) << "windows description is null";
return;
}
CFIndex count = CFArrayGetCount(desc);
qCDebug(actOp) << "finded " << count << " window";
QList<quint32> allWindows;
for(CFIndex i=0; i<count; i++)
{
CFDictionaryRef dictionary = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(desc, i));
quint32 id;
CFNumberGetValue(static_cast<CFNumberRef>(CFDictionaryGetValue(dictionary, kCGWindowNumber)),
kCFNumberSInt32Type, &id);
allWindows << id;
}
CFRelease(desc);
CFRelease(windows);
do
{
QThread::currentThread()->msleep(100);
windows = CGWindowListCreate(option, id);
desc = CGWindowListCreateDescriptionFromArray(windows);
count = CFArrayGetCount(desc);
for(CFIndex i=0; i<count; i++)
{
CFDictionaryRef dictionary = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(desc, i));
quint32 id;
CFNumberGetValue(static_cast<CFNumberRef>(CFDictionaryGetValue(dictionary, kCGWindowNumber)),
kCFNumberSInt32Type, &id);
if(allWindows.contains(id))
continue;
QString name = QString::fromCFString(static_cast<CFStringRef>(
CFDictionaryGetValue(dictionary, kCGWindowOwnerName)));
qCDebug(actOp) << static_cast<CFNumberRef>(CFDictionaryGetValue(dictionary, kCGWindowNumber))
<< " "
<< static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, kCGWindowOwnerName));
if(name.contains(m_browserTitle))
{
m_currentWindow->mac = id;
qCDebug(actOp) << "window is finded";
return;
}
else
allWindows << id;
}
CFRelease(desc);
CFRelease(windows);
}
while(m_currentWindow->mac == 0 && !timer.hasExpired(maxTime));
I tried to look in the direction of QWindow, but could not find how to get NSView, for the method Window::fromWinId, having only the desired window CGWindowID.
Tell me how you would implement such a task. Thanks.
I am attempting to build my own custom QAbstractNetworkCache implementation for use with QNetworkAccessManager.
I am having trouble with QAbstractNetworkCache::insert(QIODevice *device); inside this method, the device always arrives with 0 bytes to read from.
As I understand, the QIODevice* that is returned from QAbstractNetworkCache::prepare(const QNetworkCacheMetaData &metaData) is going to be filled with data and used as a parameter to QAbstractNetworkCache::insert(QIODevice *device) method once QNetworkAccessManager finishes downloading.
So I have prepared a QBuffer to be this container, but whenever QAbstractNetworkCache::insert(QIODevice *device) is getting called, it always arrives with nothing in it (device->bytesAvailable() == 0)
QIODevice* NetworkCachePrivate::prepare(const QNetworkCacheMetaData &metaData) {
if (!metaData.isValid() || !metaData.url().isValid() || cacheDir.isEmpty()) return 0;
QIODevice* device = 0;
QString hash = hexMD5(metaData.url().toString());
QScopedPointer<QBuffer> buffer(new QBuffer);
if (buffer->open(QIODevice::ReadWrite))
{
qDebug() << "BUFFER READY";
device = buffer.take();
deviceMapping[device] = qMakePair(hash, metaData);
}
return device;
}
void NetworkCachePrivate::insert(QIODevice *device) {
if (deviceMapping.contains(device))
{
QPair<QString, QNetworkCacheMetaData> pair = deviceMapping[device];
QString fileName;
fileName += cacheDir;
fileName += QLatin1String("/");
fileName += pair.first;
qDebug() << "DEVICE BYTES" << device->bytesAvailable(); //ALWAYS 0!!!! :(
QFile file(fileName);
if (file.open(QIODevice::WriteOnly))
{
qint64 size = file.write(device->readAll());
if (size <= 0)
{
file.remove();
}
else
{
qDebug() << "FILE WROTE " << size;
cacheSize += size;
}
}
deviceMapping.remove(device);
delete device;
}
}
QNetworkCacheMetaData NetworkCachePrivate::metaData (const QUrl &url ) {
QString fileName;
fileName += cacheDir;
fileName += QLatin1String("/");
fileName += hexMD5(url.toString());
QNetworkCacheMetaData data;
if (!QFile::exists(fileName))
return data;
data.setUrl(url);
data.setExpirationDate(QDateTime::currentDateTime().addYears(1));
return data;
}
As peppe also pointed out in the comment, you need to seek the QBuffer to the beginning after the write and before the read as per the documentation:
QBuffer allows you to access a QByteArray using the QIODevice interface. The QByteArray is treated just as a standard random-accessed file. Example:
QBuffer buffer;
char ch;
buffer.open(QBuffer::ReadWrite);
buffer.write("Qt rocks!");
*** buffer.seek(0); ***
buffer.getChar(&ch); // ch == 'Q'
buffer.getChar(&ch); // ch == 't'
buffer.getChar(&ch); // ch == ' '
buffer.getChar(&ch); // ch == 'r'
To be more concrete for your code, you would need to insert the statement like this:
...
device.seek(0);
qDebug() << "DEVICE BYTES" << device->bytesAvailable(); //NOT 0 ANYMORE!!!! :)
...
I am new on QT an I try to print out from QTableView
How can I do this?
Thank a lot
Here is a variation of the first answer that gets rid of the intermediate file.
QString strStream;
QTextStream out(&strStream);
const int rowCount = pPublic->tableView->model()->rowCount();
const int columnCount = pPublic->tableView->model()->columnCount();
out << "<html>\n"
"<head>\n"
"<meta Content=\"Text/html; charset=Windows-1251\">\n"
<< QString("<title>%1</title>\n").arg(strTitle)
<< "</head>\n"
"<body bgcolor=#ffffff link=#5000A0>\n"
"<table border=1 cellspacing=0 cellpadding=2>\n";
// headers
out << "<thead><tr bgcolor=#f0f0f0>";
for (int column = 0; column < columnCount; column++)
if (!pPublic->tableView->isColumnHidden(column))
out << QString("<th>%1</th>").arg(pPublic->tableView->model()->headerData(column, Qt::Horizontal).toString());
out << "</tr></thead>\n";
// data table
for (int row = 0; row < rowCount; row++) {
out << "<tr>";
for (int column = 0; column < columnCount; column++) {
if (!pPublic->tableView->isColumnHidden(column)) {
QString data = pPublic->tableView->model()->data(pPublic->tableView->model()->index(row, column)).toString().simplified();
out << QString("<td bkcolor=0>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
}
}
out << "</tr>\n";
}
out << "</table>\n"
"</body>\n"
"</html>\n";
QTextDocument *document = new QTextDocument();
document->setHtml(strStream);
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer, NULL);
if (dialog->exec() == QDialog::Accepted) {
document->print(&printer);
}
delete document;
here is my solution of a problem. May be it's too complex... But here you could find more solutions!
1). first I have saved table data to HTML page file:
bool CRefViewerDlg::createHtmlTableFromModel() {
// make a html-dump of table view
if (tableView) {
const QString htmlFileName = QString("%1/%2").arg(qApp->applicationDirPath()).arg("myTable.html");
QFile file(htmlFileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
MSG(QString("Can`t create file %1").arg(htmlFileName));
return false;
}
QTextStream out(&file);
const xbLong rowCount = tableView->model()->rowCount();
const xbLong columnCount = tableView->model()->columnCount();
out << "<html>\n"
"<head>\n"
"<meta Content=\"Text/html; charset=Windows-1251\">\n"
<< QString("<title>%1</title>\n").arg(refTitleName)
<< "</head>\n"
"<body bgcolor=#ffffff link=#5000A0>\n"
"<table border=1 cellspacing=0 cellpadding=2>\n";
// headers
out << "<tr bgcolor=#f0f0f0>";
for (xbLong column = 0; column < columnCount; column++)
if (!tableView->isColumnHidden(column))
out << QString("<th>%1</th>").arg(tableView->model()->headerData(column, Qt::Horizontal).toString());
out << "</tr>\n";
file.flush();
// data table
for (xbLong row = 0; row < rowCount; row++) {
out << "<tr>";
for (xbLong column = 0; column < columnCount; column++) {
if (!tableView->isColumnHidden(column)) {
QString data = tableView->model()->data(tableView->model()->index(row, column)).toString().simplified();
out << QString("<td bkcolor=0>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
}
}
out << "</tr>\n";
}
out << "</table>\n"
"</body>\n"
"</html>\n";
file.close();
}
return true;
}
2). after I have saved html content to file, it was opened in html view window, where I could print the document with QTextBrowser class:
void CLiveListDlg::on_printPageToolButton_clicked() {
#ifndef QT_NO_PRINTER
QTextBrowser *editor = static_cast<QTextBrowser* >(textBrowser);
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer, this);
dialog->setWindowTitle(tr("Print Document"));
if (editor->textCursor().hasSelection())
dialog->addEnabledOption(QAbstractPrintDialog::PrintSelection);
if (dialog->exec() != QDialog::Accepted)
return;
editor->print(&printer);
#endif
}
How about this one?
Traverse through the model of your QTableView let's say QStandardItemModel. Obtain the each and individual texts of the items available in the QStandardItemModel.
Now using QTextCursor, insert the obtained texts from your model into QTextDocument. You can make use of the examples given here to insert text into QTextDocument.
After the completion of inserting into QTextDocument, you can print the contents available in the QTextDocument through
void QTextDocument::print ( QPrinter * printer ) const
The thing you have to make sure is that you should be able to traverse through each items so that you can able obtain all the item text from the model.
Hope it helps..