B4J Question xGantt class. Duration of tasks by ours instead of days .

javiers

Active Member
Licensed User
Longtime User
Is it possible to have the duration of tasks by hours?
xGantt class is great ( @klaus ), but I wish the duration could be expressed in hours (1...24) for each day.

I would appreciate the help.
 
Last edited:
Solution
Attached version 0.98.
Tested with B4J and B4A, not B4i yet.
Please test it, and when it works also for you, i will then publish it as b4xlib Library.

1725538982516.png


What you can do:
- Change the texts, adapt them to your language.

1725539001620.png


- Hide the ID and or the Responsible column.

1725539028692.png


- When you click on a row and move the mouse, the data of that row is displayed.

1725539094854.png


- When you click on an arrow, the diagram jumps to show the beginning of the task or group.

1725539715813.png
1725539736172.png


- You can take a snapshot of the current display with the Snapshot method which returns a B4XBitmap.

EDIT 2024.09.13
I have removed the zip file.
You find the latest version in the xGanttLite thread.

klaus

Expert
Licensed User
Longtime User
This would be a big improvement and therefore change and will also be a new big challenge to add it.
It would need to redefine the task data, days or hours, and have two different managing and displaying modes for the time axis.
Then, come the details:
24 hours per day or only working hours, then define begin and end hour, and then what about overtime hours etc.
I know, some more questions, but these will define the data structure.
As it will be a lot of hours of work and I am not sure that i will take up the challenge as you are the first user seeming to be really interested in this class.
I will look at it during the next week what it really implies and let you know.
 
Upvote 0

javiers

Active Member
Licensed User
Longtime User
First thanks for answering.
I know it's a complex task and I would totally understand if you didn't tackle it. For me it would be enough if it were only 24 hours a day, no working hours or extra hours are necessary...
My intention is to be able to manage tasks related to fire services. The management of an incident can occur at any time of the day (hence the need to do it 24 hours a day) and the different tasks (related to people, fire, techniques, water supply, etc.) can correspond to different work groups, so your class is very well suited to this purpose. Maybe it can be a first approximation...
Thank you anyway for all your work. You are a reference, I have followed you for a long time!

By the way, I was wrong when I made the post here.
I have duplicated it in B4J Questions. I don't know if it is appropriate to continue on this or Erel can delete it. I don't know how to do it. I apologize...
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
With your comments, I would not use the xGantt class.
I would make a new project from scratch adapted to your needs.
This would be easier and much more efficient than trying to adapt an existing library which was not designed for your needs.
Can you give some more details on what you want to do.
Do you already have something for the managements of the incidents ?
It seems to me that a database could be very interesting to manage the incidents, the firemen, the material etc.
This would allow to filter the data with different criteria.
I see here two major parts of the project:
1. The data management
2. The display.
2.1 Calendar display.
2.2 Data display on the calendar.

If you give more details I might have a look at this.
The first step would be to display the calendar.
In parallel you need to define the data structure:
How you want to combine the different data and what you want to display on the calendar.
 
Last edited:
Upvote 0

javiers

Active Member
Licensed User
Longtime User
Thanks again for your involvement. And excuse my English, I'm using Google translator.
I've used a Kanban board project that's on the forum (sorry if I don't mention the author) to manage the tasks that are being performed in an incident. Basically, the structure is as follows:
1. A card/task is created that contains the description, a color corresponding to a certain color code, sector (physical or virtual) where the task is performed, the assigned resource/s and a field for notes. The task has three possible states: Planned, in progress, completed.
Depending on that state, the task is moved to the appropriate area of the board.
I use SQLite, and there are basically two tables, cards and objectives.
I show you the images of the application and the database...

1724493980047.png
1724494053641.png

1724494100952.png
 
Upvote 0

javiers

Active Member
Licensed User
Longtime User
I believe that this information, presented in the format of a simple Gantt chart (no precedence or successor data are necessary, etc.) makes it easier for the commander to have a better overview of the incident. Note: a field is missing in the task, which is the agency or service of the resource that performs the task (firefighters, paramedics, technicians, police, etc.).

1724494699874.png


1724494282962.png

1724494299940.png
 

Attachments

  • SitacTareas.zip
    5 KB · Views: 69
Upvote 0

klaus

Expert
Licensed User
Longtime User
Attached you find a demonstrator project for your display.
It is a B4XPages project and the graphic display is a CustomView called xTimeCalendar.
It needs more work to fit exactly what you want or need.
There is no scrolling yet, but this will depend on your display requirements.
There are more questions:
- How many days do you want to display ?
This might need the scrolling.
- How do you think you will prepare the data for the display ?
Currently the display data is organized in rows.
Each row has this Structure:
B4X:
    Type IncidentData(ID As String, Title As String, BeginTime As String, EndTime As String, Color As Int)
When the ID is empty only the Title is displayed or if the Title is empty nothing is displayed.

1724657190797.png


EDIT: 2024.09.02
I have removed the zip file.
 
Last edited:
Upvote 0

javiers

Active Member
Licensed User
Longtime User
Attached you find a demonstrator project for your display.
It is a B4XPages project and the graphic display is a CustomView called xTimeCalendar.
It needs more work to fit exactly what you want or need.
There is no scrolling yet, but this will depend on your display requirements.
There are more questions:
- How many days do you want to display ?
This might need the scrolling.
- How do you think you will prepare the data for the display ?
Currently the display data is organized in rows.
Each row has this Structure:
B4X:
    Type IncidentData(ID As String, Title As String, BeginTime As String, EndTime As String, Color As Int)
When the ID is empty only the Title is displayed or if the Title is empty nothing is displayed.

View attachment 156376
Ugh, thanks for the work!
I'm going to answer you:
Incidents usually don't last more than 3 days (they are usually resolved sooner), but that duration would be fine. Horizontal and vertical displacement is therefore necessary.

The organization of the data is perfect like this. I would add two more columns: Agency or service responsible for the task and another that indicates the status of the task (P - planned, C - in progress, F - completed).

For asking (I hope I don't overdo it), there is an event that when clicking on a task can return the row() data, and thus be able to link to the database record.

I know there are many things, the effort seems great to me, so how far to go is in your hands...
Thank you very much!!
 

Attachments

  • propuesta.png
    propuesta.png
    39.1 KB · Views: 60
Upvote 0

klaus

Expert
Licensed User
Longtime User
The organization of the data is perfect like this. I would add two more columns: Agency or service responsible for the task and another that indicates the status of the task (P - planned, C - in progress, F - completed).
Will be added.

For asking (I hope I don't overdo it), there is an event that when clicking on a task can return the row() data, and thus be able to link to the database record.
This was already on my to do list.
I wanted to first have your feedback with more information

I know there are many things, the effort seems great to me, so how far to go is in your hands...
I will go further.

Other questions :
1. Are the comments in the database encrypted ? The texts look strange.
2. Looking at the example in post #6, are all the rows considered as one intervention with different tasks ore are all considered independently ?
3. How are the time stamps saved in the database, I suppose as Strings and not as time Ticks.
4. You have 4 time stamps in the database, what do they represent ?
Do they indirectly indicate the status (P - planned, C - in progress, F - completed)?
horaInicio = begin time, incident has begun ?
horaPrevista = scheduled begin time, incident has not begun ?
horaCurso = current time, incident is in progress ?
horaFin = end time, incident is finished ?
 
Last edited:
Upvote 0

javiers

Active Member
Licensed User
Longtime User
Will be added.


This was already on my to do list.
I wanted to first have your feedback with more information


I will go further.

Other questions :
1. Are the comments in the database encrypted ? The texts look strange.
2. Looking at the example in post #6, are all the rows considered as one intervention with different tasks ore are all considered independently ?
3. How are the time stamps saved in the database, I suppose as Strings and not as time Ticks.
4. You have 4 time stamps in the database, what do they represent ?
Do they indirectly indicate the status (P - planned, C - in progress, F - completed)?
horaInicio = begin time, incident has begun ?
horaPrevista = scheduled begin time, incident has not begun ?
horaCurso = current time, incident is in progress ?
horaFin = end time, incident is finished ?

Thanks again.

1.- The tables are not encrypted. The text is an example and is written randomly - meaningless.
2.- That is. This is a single incident, with different agencies carrying out tasks (one intervention with different tasks).
3.-The times are recorded in DATETIME fields.

CREATE TABLE cards (
cardID INTEGER,
color VARCHAR,
tareatxt VARCHAR,
tareaico VARCHAR,
sector VARCHAR,
recurso VARCHAR,
horaInicio DATETIME,
top INTEGER,
INTEGER,
notas VARCHAR,
horaPrevista DATETIME,
horaCurso DATETIME,
horaFin DATETIME
);

4.-
The process would be:
1.- When creating the task, its initial status is indicated:
a )If Planned --> horaPrevista --> horaInicio
b)If In progress --> horaCurso --> horaInicio
c) If Finished --> horaFin --> horaInicio
horaInicio will be updated with the time of the state change that occurs.

A task can have its status updated by going from
Planned --> In Progress
Planned --> Finished
In progress --> Finished​
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Thank you for the information.
One more question concerning the database time stamps:
Is the database SQLite or another one ?
Because SQLite has no specific DATETIME format.
I have seen that the dates have this format: "yyyy-MM-dd HH:mm:ss"
When you add them into the database, what is added? A String or a Long ?
When you read them back, are you using a String or a Long or an Int ?
 
Last edited:
Upvote 0

javiers

Active Member
Licensed User
Longtime User
You're right. Although it let me put it as DATETIME, but I think it really does it as a string. And the format is "dd-MM-yyyy HH:mm:ss". I read it as string.
1724690295443.png
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Some more questions:
1. When you plan a task, do you enter an estimated begin time and a duration or an estimated begin time and end time ?
2. Do you treat an incident as a kind of group of tasks with its own ID, or are they treated only with an ID which could have a reference to the incident ?

I think, with this project, I will make a kind of mini Gantt chart, which could be useful for other users, not only for your specific needs.
 
Last edited:
Upvote 0

javiers

Active Member
Licensed User
Longtime User
When we manage an incident we don't know the duration of the task. As far as I'm concerned, starting the task and using an initial duration of 1 or 2 hours would be correct. Normally, situation assessments are carried out, which would allow the duration of the task to be increased in case it hasn't finished yet.

I think tasks, which have their task ID, should also have a common Incident ID field. (Did I understand this question correctly?)

I'm sure it would be very useful for other users, since you're putting it in a way that it's applicable to other purposes. It certainly seems that way to me. And thank you, thank you again.
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Attached you find the current version of the xGanttLite Class.
It is still a work in progress, but I post it now because the two next day I have no time for B4X.

You can test the demo project and send your feedback.

1724963206826.png


EDIT: 2024.09.02
I have removed the zip file.
You find the latest version in the xGanttLite thread.
 
Last edited:
Upvote 0

klaus

Expert
Licensed User
Longtime User
Attached the current version.

1725299735452.png


When you press on the diagram the data of the current row is displayed in panel moving with the cursor.

Some questions:
1. How do you define Planned, InProgress and Finished ?
In the current version:
Tasks with an end before NOW the red vertical line, are considered finished and displayed with a full line.
Tasks with a beginning after NOW are considered as Planned and displayed with an empty line.
The others are considered in progress and the line is full before NOW and empty after Now.
Is this behavior OK for you ?

2. The Comment has not yet been introduced.
How long are the longest comments ?
This may change the position of the display of the current row.

EDIT 2024.09.13
I have deleted the zip file.
You find the latest version in the xGanttLite thread.
 
Last edited:
Upvote 0

javiers

Active Member
Licensed User
Longtime User
First, thanks again!
I think the way tasks are displayed according to their status is perfect.
I've been testing the previous version and what I've done is load the data from SQLite in groups, with the following criteria:
Planned --> They are tasks planned when startTime == plannedTime
InProgress --> They are tasks in Progress when startTime == courseTime. It puts the end time as 3 hours more than the current one.
Finished --> They are tasks in Finished when startTime == endTime
But the way you propose to represent them is very correct!

Loading data in groups:
Sub IniciaCargaDatos

    'Son tareas previstas cuando horaInicio == horaPrevista
    Private TaskList As List
    TaskList.Initialize   
    Dim Cursor, Cursor2, Cursor3 As ResultSet

    Cursor = SQL1.ExecQuery("Select DISTINCT sector, color FROM cards WHERE  horaInicio = horaPrevista ORDER BY rowid")
    Do While Cursor.NextRow
        Log(Cursor.GetString("sector"))
        If Cursor.GetString("sector") <> Null Then
            FireIncidents.AddGroup(Cursor.GetString("sector") & "-P", Cursor.GetString("sector"), TaskList, Cursor.GetInt("color"))
            Cursor2 = SQL1.ExecQuery2("SELECT DISTINCT recurso FROM cards WHERE sector = ?  AND horaInicio = horaPrevista ORDER BY recurso", Array As String(Cursor.GetString("sector")))
            Do While Cursor2.NextRow
                TaskList.Add(Cursor2.GetString("recurso"))
            Loop

            Cursor3 = SQL1.ExecQuery2("SELECT * FROM cards WHERE sector = ?  AND horaInicio = horaPrevista ORDER BY recurso", Array As String(Cursor.GetString("sector")))
                Do While Cursor3.NextRow
                    'pONE COMO FIN 3 HORAS MÁS DE LA ACTUAL
                FireIncidents.AddTask(Cursor3.GetString("recurso"), Cursor3.GetString("tareatxt"), "Manuel", Cursor3.GetString("horaPrevista"),DateTime.Date(DateTime.Now + DateTime.TicksPerHour*3), Cursor3.GetString("color"))
            Loop
        End If

    Loop

    'Son tareas en Curso cuando horaInicio == horaCurso
    FireIncidents.AddEmpty
    

    Cursor = SQL1.ExecQuery("Select DISTINCT sector, color FROM cards WHERE  horaInicio = horaCurso ORDER BY rowid")
    Do While Cursor.NextRow
        Log(Cursor.GetString("sector"))
        If Cursor.GetString("sector") <> Null Then
            FireIncidents.AddGroup(Cursor.GetString("sector") & "-C", Cursor.GetString("sector"), TaskList, Cursor.GetInt("color"))
            Cursor2 = SQL1.ExecQuery2("SELECT DISTINCT recurso FROM cards WHERE sector = ? AND horaInicio = horaCurso ORDER BY recurso", Array As String(Cursor.GetString("sector")))
            Do While Cursor2.NextRow
                TaskList.Add(Cursor2.GetString("recurso"))
            Loop

            Cursor3 = SQL1.ExecQuery2("SELECT * FROM cards WHERE sector = ? AND horaInicio = horaCurso ORDER BY recurso", Array As String(Cursor.GetString("sector")))
            Do While Cursor3.NextRow
                'pONE COMO FIN 3 HORAS MÁS DE LA ACTUAL
                    FireIncidents.AddTask(Cursor3.GetString("recurso"), Cursor3.GetString("tareatxt"), "Manuel", Cursor3.GetString("horaCurso"),DateTime.Date(DateTime.Now + DateTime.TicksPerHour*3), Cursor3.GetString("color"))
            Loop

        End If

    Loop

    'Son tareas en Finalizadas cuando horaInicio == horaFin
    FireIncidents.AddEmpty

    Cursor = SQL1.ExecQuery("Select DISTINCT sector, color FROM cards WHERE  horaInicio = horaFin ORDER BY rowid")
    Do While Cursor.NextRow
        Log(Cursor.GetString("sector"))
        If Cursor.GetString("sector") <> Null Then
            FireIncidents.AddGroup(Cursor.GetString("sector") & "-F", Cursor.GetString("sector"), TaskList, Cursor.GetInt("color"))
            Cursor2 = SQL1.ExecQuery2("SELECT DISTINCT recurso FROM cards WHERE sector = ? AND horaInicio = horaFin ORDER BY recurso", Array As String(Cursor.GetString("sector")))
            Do While Cursor2.NextRow
                TaskList.Add(Cursor2.GetString("recurso"))
            Loop

            Cursor3 = SQL1.ExecQuery2("SELECT * FROM cards WHERE sector = ? AND horaInicio = horaFin ORDER BY recurso", Array As String(Cursor.GetString("sector")))
            Do While Cursor3.NextRow
                FireIncidents.AddTask(Cursor3.GetString("recurso"), Cursor3.GetString("tareatxt"), "Manuel", Cursor3.GetString("horaPrevista"), Cursor3.GetString("horaFin"), Cursor3.GetString("color"))
            Loop
        End If

    Loop
    
    Cursor.Close
    Cursor2.Close
    Cursor3.close
End Sub





When you're managing an incident, it's quite common to anticipate and plan tasks that have a start before NOW, but it doesn't influence your proposal, so it seems perfect to me.

Ok for the Responsible column. It's necessary.
The comment field shouldn't be too long, I think a maximum of 50 would be reasonable, but as you see, it shouldn't be a problem

And again thanks for such work!!
1725304559975.png
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Some more comments on the class:
- You can hide or show the Row and the Responsible columns, this can be changed in the Designer and in the code in next version, the ID and Name columns remain.
- You can change the names of the columns to adapt them to your language the same will be done for the other words in the future.
 
Upvote 0
Top