I have an app that has text appended to a TextArea (TA). It automatically scrolls to keep the recent line added in view. Over time, this could be a lot. Do I have to worry about this? Is there an upper limit? And, if so, how can I prune the oldest lines of text?
There's nothing in the documentation, but if it gets too big you could run into memory issues. But we're talking collosal here.
It's easy enough to remove oldest lines using the slice() method
Related
I'm relatively new to JavaFX and have written a small applet which launches a number of (typically between 3 and 10) sub-processes. Each process has a dedicated tab displaying current status and a large TextArea where the process output is appended to. For simplicity all tabs are generated on startup.
javafx.application.Platform.runLater(() -> logTextArea.appendText(line)))
The applet works fine when workloads on sub-processes are low-moderate (not many logs), but starts to freeze when sub-processes are heavily used and generate a decent amount of logging output (a good few hundreds of lines per second in total).
I looked into binding the TextArea to the output, but my understanding is it effectively calls the Platform.runLater() method so there will still be hundreds of calls to JavaFX application thread per second.
Batching logging outputs isn't an ideal solution either because I'd like to keep the displayed log as real-time as possible.
The only solution which I think might solve the problem seems to be dynamic loading of individual tabs. This would definitely prevent unnecessary calls to update logging textareas that aren't currently visible, but before I go ahead to make the changes, I'd like to get some helpful advice from you here. Thanks!
Thanks for all your suggestions. Finally got around to implementing a fix today.
The issue was fixed by using a buffer coupled with a secondary check for time lapse (maximum 20 lines or 100 ms).
In addition, I also implemented rolling output to limit the total process output to 1,000 lines.
Thanks again for your invaluable contribution!
I'd like to make a pause screen.
In the game the view follows the character and when paused I want the text to be exactly in the middle of the screen. I am using a draw GUI event to display text where the user can see it.
I was thinking of halving the length and width of the port but could not find a function which gave those numbers.
If there is one, what it is, and if not how can I achieve this?
I think I have solved this.
In the GUI event, I use view_hport[0] and view_wport[0] in order to obtain the total length of the port then halve this number.
For a QTextEdit* te I have noticed that sometimes te->document()->size() returns (0,0) and sometimes it returns the actual size. In both cases, te->toPlainText() returns non-empty text.
What can be done for it to return the size?
Is there some refresh method so the document will definitely return the size after it?
Try to call QApplication::processEvents() before checking size. It will cause processing of all pending Qt events, so after this call all sizes will be updated. Note that invisible documents still may not return correct size.
Calculating layout of text is heavy operation, especially when text is long, so this have to be delayed as possible. I'm pretty sure that you get this zero size somewhere in construction time.
How you can overcome this problem?
Best approach is lazy initialization. Do not perform calculation until some value is relay needed (it you do this properly you will never get zero size).
Other approach is to enforce calculation of document layout. You can do it by calling setTextWidth(), setPageSize() or idealWidth() depending on context of your task.
idealWidth() is perfect if you do not wrap lines and don't have page size.
I'm writing a download manager, and I've noticed that all the web pages I've encountered don't seem to set the ContentLength header, whereas other media types (images) do. However, when I load a page (in Firefox), I get a progress as it loads. What's that based off if not file size?
Because a web page may be the sum of many downloads, any of which may have an unknown size, the progress is more the number of items completed compared to the number of items requested than a precise measure of bytes. And I think most browsers include dns resolution as a significant chunk of the progress.
First choose an amount of progress to give to dns, redirects and other handshake involved in getting the first byte of the main document, say 20% of total. When you get the first byte of the main document, you are at 20% progress.
You might also reserve a little tail space of the progress for running javascripts and doing page layout. Say another 10% leaving 70% to represent downloads.
As the main document is downloading, count all the additional resources that will need to be downloaded. If there are 50 additional resources, then the main document represent 2% of the remaining 70% of the download, so when it finishes you are at almost 22% progress regardless of how big it was. As each of those 50 resources arrives the progress goes up a little.
You might weight things as the size becomes known or even by type. So maybe css files count as 1 item, images as 3 and movies as 10. For any of these items that the size is given, you can increment the overall progress more precisely.
In a nutshell, it is an aggregate progress bar representing any number of tasks. Even if the number of bytes for a given task is known the time is not.
Every progress bar is a guess. If you want to know what guesses Firefox makes, its source code is open for public viewing.
I am attempting to use DirectShow to play two AVI files consecutively (one after the other) so that there is no interruption in the audio or video when the player transitions from one file to the next.
I have two custom controls on my form. Each one is pre-loaded with an AVI file, and before playback begins I set up all the DirectShow interfaces, set the video windows and resize them, call IMediaControl.Run(), then IMediaControl.Pause(), then IMediaSeeking.SetPositions to reset to frame 0, on both controls. On the form, you can see that both files are paused at their initial frames.
I then call IMediaControl.Run() on the first control, and wait for it to complete before calling Run() on the second control. Initially, I hooked into the first video's EC_COMPLETE notification message, and used this to start the second. Thinking that this event might be slow to arrive (turns out it is, but for a weird reason), I tried two other approaches:
Check the first video's current position inside a timer that goes off every second or so (using IMediaPosition.get_CurrentPosition). When the current position is within a second of the video's stop time (known in advance from IMediaPosition.get_StopTime), I go into a tight while loop and wait for the current position to equal the stop time, and then call Run() on the second video.
Same as the first, except I replace the while loop with a call to timeSetEvent from winmm.dll, with a delay set so that it fires right when the first file is supposed to end. I use the callback to Run() the second file.
Either of these two methods substantially cuts down the delay between the end of the first file and the beginning of the second, indicating that the EC_COMPLETE message doesn't arrive immediately after the file is complete (I also tried hooking the EC_SEGMENT_COMPLETE message, which is supposed to be used for looping within a file, but apparently nobody supports this - it never occurs on my machine, at least).
Doing all of the above has cut the transition delay from as much as a second, down to a barely perceptible glitch; about a third of the time the files transition with no interruption at all, which suggests there's no fundamental reason I can't get this to work all the time.
The slight delay is still unacceptable, unfortunately. I assume (and I could easily be wrong) that the remaining delay is due to a slight variable delay between the call to IMediaControl.Run() and when the video actually starts playing.
Does anybody know anything I can do to eliminate this little lag? It would also help to be told this is fundamentally impossible for whatever reason, which wouldn't surprise me. I've never encountered a video player in Windows that doesn't have this problem, so it may not be doable.
More info: the AVI files I'm playing are completely uncompressed (video and audio are uncompressed), so I don't think the lag is due to DirectShow's having to uncompress the video ahead of play start, although it may still buffer ahead as matter of course (and this may be the source of the problem). I would have though that starting play, pausing and then rewinding to the beginning would fix this.
Also, the way I'm handling the transition is to actually have the second control underneath the first; when the first completes playing, I start the second and then call BringToFront on it, creating the appearance of a single video transitioning between the two originals. I don't think the glitch is due to this, because it works perfectly some of the time, and even if this were problematic, it wouldn't explain the matching audio glitch.
Even more: I just tried starting the second video 30-50 milliseconds "early" and that seemed to eliminate even more of the gap, so I'm guessing that the lag in Run() is about that long. It appears to be variable, though, so this is still not where I need it to be.
Still more: perhaps I could eliminate this delay by loading the AVIs from memory rather than from a file. Unfortunately, I have no idea how to do this. IMediaControl only has a RenderFile() method, not something like a RenderStream or RenderMemory method.
If you call IMediaControl::Run on a stopped graph, the graph manager will post the call to a worker thread (so there's some variability). On the worker thread, the graph will be paused. Render filters only complete a pause transition once they have received data, so once GetState() returns S_OK, the graph manager knows that the graph is fully cued. At this point, it picks a time roughly 10ms into the future, and calls Run on each filter with that time as the start point. Since it takes time to tell each filter to Run, the dshow Run method has a parameter which is the refclock time at which a sample timestamped zero should be played -- i.e. the time at which the actual transition to run mode should take place.
To synchronise this with another graph, you first have to ensure that both graphs have the same clock. Query the graph (not the filter) for IMediaFilter, and call GetSyncSource on one graph and SetSyncSource on the other. Then you need to pause the second graph, so that it is cued and ready. When you want to start it, call IMediaFilter::Run instead of IMediaControl::Run, and you can pass your own start time. This still has to be a few milliseconds into the future, so the best thing might be to set the start time of the second graph to be the first graph's start time plus its duration (for an indexed container of uncompressed streams, the duration should be accurate).
Another approach is to use multiple graphs. Separating source from rendering would allow you to switch seamlessly between sources since they feed into a common render graph. There is sample source code for this approach at www.gdcl.co.uk/gmfbridge.
G