I'm having trouble understanding how to update a widget in Tk to reflect an ongoing process.
Basically, right now my program is to recursively scan a directory and is supposed to output each directory/file it finds to a text widget one at a time. My problem is that instead of doing this, the script finds all of the directories and then outputs everything all at once when it's done. Here's the code:
proc scan {{dir .}} {
global num_items_found vs_list ec_list
foreach i [lsort [glob -nocomplain -dir $dir *]] {
if {[file type $i]=="directory"} {
.main.body.log insert end "Checking $i\n";
scan $i;
} else {
if {[string tolower [file tail $i]] eq "buildlog.htm"} {
lappend vs_list $i;
incr num_items_found;
.main.body.log insert end "Found $i\n";
} elseif {[file extension $i] eq ".log"} {
lappend ec_list $i;
incr num_items_found;
.main.body.log insert end "Found $i\n";
}
}
}
return;
}
I am also calling this proc in a different proc, in which I am also disabling a button prior to the scan and re-enabling it after; yet this doesn't work either. The script doesn't allow my widgets to update at all before the scan proc executes? How can I get the desired result?
Thanks!
Most display updates in Tk happen from the event loop. In your case, the event loop is not entered until after you finish the directory traversal. You might want to use the update idletasks command.
From the manual:
The update idletasks command is useful in scripts where changes have been made to the application's state and you want those changes to appear on the display immediately, rather than waiting for the script to complete. Most display updates are performed as idle callbacks, so update idletasks will cause them to run. However, there are some kinds of updates that only happen in response to events, such as those triggered by window size changes; these updates will not occur in update idletasks.
Related
We have integration setup that creates purchase orders on the batch server. For example the batch job may run and pick up 5 invoices coming from an external source and attempt to post them.
If 4 are successful and 1 fails, we catch the error using the code below:
errEnumerator = SysInfologEnumerator::newData(infolog.cut());
while (errEnumerator.moveNext())
{
msgStruct = new SysInfologMessageStruct(errEnumerator.currentMessage());
errException = errEnumerator.currentException();
messageBody += msgStruct.message() + "\n";
}
Which works great in catching the error and then we return it into a log. The issue is the entire message will be shown. "Number of vouchers posted to the journal 1." 4 times and then the error message.
After each successful post we do clear the infolog by doing infolog.clear();.
If you debug this code in X++ it does clear it each time and the error will only show the actual error without the previous successful posts. But the batch job running on the batch server for some reason does not clear the infolog after each successful post. After CILs, restarting services etc. nothing seems to work.
Is there another way to clear the infolog on the batch server? thanks
If your goal is to store only the error lines in messageBody and not the 'success' lines, you don't have to clear the Infolog. You only need to add the following check at the beginning of your while cycle:
if (errEnumerator.currentException() == Exception::Info ||
errEnumerator.currentException() == Exception::Warning)
{
continue;
}
Do not mess with the infolog!
This will hide information, warnings and errors that you will need for example for batch problem solving.
So please do not clear() or cut().
Instead copy what you want:
numLine = infologLine();
try
{
// Do something useful
}
catch (Exception::Error)
{
doTheLog(infolog.copy(numLine + 1, infologLine()));
throw error("That did not work!");
}
First store the current infolog number. On error process the relevant infologs.
If the infolog is long consider transferring the numbers rather than call by value the container:
doTheLog(numLine + 1, infologLine());
Then infolog.copyin the method.
I have issue using OpenCV 3 tracking module for tracking. It behaves same, either I use interface class (cv::Tracker) or class with implementation (like cv::TrackerMedianFlow or cv::TrackerMIL, etc). Sample is a bit modified sample from OpenCV sample folder
After correct creation
Ptr<Tracker> tracker = Tracker::create( tracker_algorithm );
if ( tracker == NULL )
{
std::cout << "***Error in the instantiation of the tracker...***\n";
return -1;
}
initialization works just fine
if ( !tracker->init( frame, boundingBox ) )
{
std::cout << "***Could not initialize tracker...***\n";
return -1;
}
Problem occurs late on, withing main loop, when tracking is lost. I use separate detector for defining new target. When I find new target, I clear tracker and initialize it with new value
tracker->clear( );
if ( !tracker->init( frame, detectedNewBBox) )
{
std::cout << "***Could not initialize tracker without history...***\n";
return -1;
}
However, initialization always returns false. I am trying to find out WHY tracker cannot be initialized?
Data was check few time, and looks pretty correct. I even conducted small experiment, trying to initialize tracker right after creation with same data it won't initialize withing loop and it works perfect.
Am I doing something wrong? I was unable to find any documentation on this...
Here is link to available documentation on this:
OpenCV 3 Tracker documentation
Thanks for any effort!
I just ran into the same problem, here's how I got it to work :
tracker->clear();
Ptr<Tracker> trackerNew = Tracker::create( tracker_algorithm );
tracker = trackerNew;
tracker->init( image, boundingBox );
Might not be the right way or the prettiest but it does the job :)
If you want to track a new ROI (region of interest) then I suggest that you should create a new tracker instead of clearing and trying to reuse a previous tracker. Re-use when you need to call init will provide no extra benefit. As you have observed, re-initializing a tracker is not allowed by default.
But if you want to resume tracking of the same object with your correction, it might be possible by doing following steps (I have not tried it myself yet. following code is just a pseudo code)
Ptr<TrackerModel> model = tracker->getModel();
Ptr<TrackerTargetState> lastTargetstate = getLastTargetState();
// Make changes to lastTargetState (update position etc)
// Set lastTargetState, I am not sure if you need to actually set it
// or just editing the object through pointer should work.
model->setLastTargetState(lastTargetstate);
I ran into the same problem and here's my solution:
Open the file in opencv_contrib/modules/tracking/src/tracker.cpp and apply the following changes:
- if( isInit )
+ /*if( isInit )
{
return false;
}
+ */
I recompiled opencv3 and reinstalled it. That fixed it for me. I think they did not want people to reinitialize the tracker for some reason. I am not sure why?
I have a window in a Qt application using PostgreSQL 9.3 database. The window is a form used do display, edit and insert new data. t looks like that:
I have data from 3 sql tables in that view. the tables are related with foreign keys:
contractors (main table) - mapped to "personal data" section
contacts (has foreign key to contractors.ID)
addresses (has foreign key to contractors.ID)
So - in my window's class I have 3 main models (+ 2 proxy models to transpose tables in "personal data" an "address data" sections). I use QSqlTableModel for theese sesctions, and a QSqlRelationalTableModel for contactData section. when opening that window "normally" (to view some contractor), i simply pass contractor's ID to the constructor and store it in proper variable. Also, I call the QSqlTableModel::​setFilter(const QString & filter) method for each of the models, and set the proper filtering. When opening that window in "add new" mode i simply pass a "-1" or "0" value to the ID variable, so no data gets loaded to the model.
All 3 models have QSqlTableModel::OnManualSubmit editStrategy. When saving the data (triggered by clicking a proper button), I start a transaction. And then I submit models one-by-one. personalData model gets submitted first, as I need to obtain it's PK after insert (to set in the FK fields in other models).
When submitting of the model fails, I show a messageBox with the QSqlError content, rollback the transaction and return from the method.
When I have an error on the first model being processed - no problem, as nothing was inserted. But when the first model is saved, but the second or third fails - there is a little problem. So I rollback the transacion as before, and return from the function. But after correcting the data and submitting it again - the first model is not trying to submit - as it doesn't know that there was a rollback, and the data needs to be inserted again. What would be a good way to notice such a model, that it needs to be submited once again?
At the moment I ended up with something like that:
void kontrahenciSubWin::on_btnContractorAdd_clicked() {
//QStringList errorList; // when error occurs in one model - whole transacion gets broken, so no need for a list
QString error;
QSqlDatabase db = QSqlDatabase::database();
//backup the data - in case something fails and we have to rollback the transaction
QSqlRecord personalDataModelrec = personalDataModel->record(0); // always one row. will get erased by SubmitAll, as no filter is set, because I don't have its ID.
QList<QSqlRecord> contactDataModelRecList;
for (int i = 0 ; i< contactDataModel->rowCount(); i++) {
contactDataModelRecList.append( contactDataModel->record(i) );
}
QList<QSqlRecord> addressDataModelRecList;
for (int i = 0 ; i< addressDataModel->rowCount(); i++) {
addressDataModelRecList.append( addressDataModel->record(i) );
}
db.transaction();
if ( personalDataModel->isDirty() && error.isEmpty() ) {
if (!personalDataModel->submitAll()) //submitAll calls select() on the model, which destroys the data as the filter is invalid ("where ID = -1")
//errorList.append( personalDataModel->lastError().databaseText() );
error = personalDataModel->lastError().databaseText();
else {
kontrahentid = personalDataModel->query().lastInsertId().toInt(); //only here can I fetch ID
setFilter(ALL); //and pass it to the models
}
}
if ( contactDataModel->isDirty() && error.isEmpty() )
if (!contactDataModel->submitAll()) //slot on_contactDataModel_beforeInsert() sets FK field
//errorList.append( contactDataModel->lastError().databaseText() );
error = contactDataModel->lastError().databaseText();
if ( addressDataModel->isDirty() && error.isEmpty() )
if (!addressDataModel->submitAll()) //slot on_addressDataModel_beforeInsert() sets FK field
//errorList.append( addressDataModel->lastError().databaseText() );
error = addressDataModel->lastError().databaseText();
//if (!errorList.isEmpty()) {
// QMessageBox::critical(this, tr("Data was not saved!"), tr("The following errors occured:") + " \n" + errorList.join("\n"));
if (!error.isEmpty()) {
QMessageBox::critical(this, tr("Data was not saved!"), tr("The following errors occured:") + " \n" + error);
db.rollback();
personalDataModel->clear();
contactDataModel->clear();
addressDataModel->clear();
initModel(ALL); //re-init models: set table and so on.
//re-add data to the models - backup comes handy
personalDataModel->insertRecord(-1, personalDataModelrec);
for (QList<QSqlRecord>::iterator it = contactDataModelRecList.begin(); it != contactDataModelRecList.end(); it++) {
contactDataModel->insertRecord(-1, *it);
}
for (QList<QSqlRecord>::iterator it = addressDataModelRecList.begin(); it != addressDataModelRecList.end(); it++) {
addressDataModel->insertRecord(-1, *it);
}
return;
}
db.commit();
isInEditMode = false;
handleGUIOnEditModeChange();
}
Does anyone have a better idea? I doubt if it's possible to ommit backing-up the records before trying to insert them. But maybe there is a better way to "re-add" them to the model? I tried to use "setRecord", and "remoweRows" & "insertRecord" combo, but no luck. Resetting the whole model seems easiest (I only need to re-init it, as it loses table, filter, sorting and everything else when cleared)
I suggest you to use a function written in the language PLPGSQL. It has one transaction between BEGIN and END. If it goes wrong at a certain point of the code then will it rollback all data flawlessly.
What you are doing now is not a good design, because you handle the control over a certain functionality (rollback) to an external system with regard to the rollback (it is happening in the database). The external system is not designed to do that, while the database on the contrairy is created and designed for dealing with rollbacks and transactions. It is very good at it. Rebuilding and reinventing this functionality, which is quite complex, outside the database is asking for a lot of trouble. You will never get the same flawless rollback handling as you will have using functions within the database.
Let each system do what it can do best.
I have met your problem before and had the same line of thought to work this problem out using Hibernate in my case. Until I stepped back from my efforts and re-evaluated the situation.
There are three teams working on the rollback mechanism of a database:
1. the men and women who are writing the source code of the database itself,
2. the men and women who are writing the Hibernate code, and
3. me.
The first team is dedicated to the creation of a good rollback mechanism. If they fail, they have a bad product. They succeeded. The second team is dedicated to the creation of a good rollback mechanism. Their product is not failing when it is not working in very complex situations.
The last team, me, is not dedicated to this problem. Who am I to write a better solution then the people of team 2 or team 1 based on the work of team 2 who were not able to get it to the level of team 1?
That is when I decided to use database functions instead.
I have designed an AIR application that displays a list with all txt files located in C:\ directory. I have used following code:
var videoListsArr:ArrayList = new ArrayList();
var folder:File = new File(driveName+":\\");
folder.getDirectoryListingAsync();
folder.addEventListener( FileListEvent.DIRECTORY_LISTING, handleDirectoryListing );
private function handleDirectoryListing( event:FileListEvent ):void
{
for each(var item:File in event.files)
{
var itemExtn:String = (item.extension != null) ? item.extension.toLocaleLowerCase() : null;
if(item.isDirectory)
{
item.getDirectoryListingAsync();
item.addEventListener( FileListEvent.DIRECTORY_LISTING, handleDirectoryListing );
}
else if(!item.isSymbolicLink && itemExtn != null)
{
if(itemExtn == "txt")
videoListsArr.addItem(txt);
}
}
}
This function works fine but it is being executed the application is hang and become unresponsive. Please tell me how to resolve this problem that it displays the list of txt file without making application unresponsive ?
from what i can see, you're getting a directory, looking at all the files in there, and if one of them is a directory, you look at all the files etc recursively, which could end up being very heavy depending on the start folder. remove the first if check and tell me if it's still unresponsive
I use a timer to break up the processing. My timer subclasses Timer to add a files:Array and a directories : Array.
The initial handler that processed the top-level directory (in my case, loadDirectoryHandler) loads the timer.files with all the files it cannot processes immediately as well as all the sub-directories,
On each cycle through the TIMER handler, it slices out a chunk of the files Array (e.g. 200 files), processes that, and then starts the timer if there are any left so they get processed on the next TIMER event.
For each directory, it takes the File object and
file.addEventListener( FileListEvent.DIRECTORY_LISTING, loadDirectoryHandler );
file.getDirectoryListingAsync();
Cheers
I recently started this question in another thread (to which Reed Copsey
graciously responded) but I don't feel I framed the question well.
At the core of my question, I would like an illustration of how to gain
access to data AS it is being get/set.
I have Page.aspx.cs and, in the codebehind, I have a loop:
List<ServerVariable> files = new List<ServerVariable>();
for (i = 0; i <= Request.Files.Count - 1; i++)
{
m_objFile = Request.Files[i];
m_strFileName = m_objFile.FileName;
m_strFileName = Path.GetFileName(m_strFileName);
files.Add(new ServerVariable(i.ToString(),
this.m_strFileName, "0"));
}
//CODE TO COPY A FILE FOR UPLOAD TO THE
//WEB SERVER
//WHEN THE UPLOAD IS DONE, SET THE ITEM TO
//COMPLETED
int index = files.FindIndex(p => p.Completed == "0");
files[index] = new ServerVariable(i.ToString(),
this.m_strFileName, "1");
The "ServerVariable" type gets and sets ID, File, and Completed.
Now, I need to show the user the file upload "progress" (in effect,
the time between when the loop adds the ServerVariable item to the
list to when the Completed status changes from 0 to 1.
Now, I have a web service method "GetStatus()" that I would like to
use to return the files list (created above) as a JSON string (via
JQuery). Files with a completed status of 0 are still in progress,
files with a 1 are done.
MY QUESTION IS - what does the code inside GetStatus() look like? How
do I query List **as* it is being populated and
return the results real-time? I have been advised that I need to lock
the working process (setting the ServerVariable data) while I query
the values returned in GetStatus() and then unlock that same process?
If I have explained myself well, I'd appreciate a code illustration of
the logic in GetStatus().
Thanks for reading.
Have a look at this link about multi threading locks.
You need to lock the object in both read and write.