View Full Version : [VB.NET] Aiuto immagine di attesa caricamento tra form
Buongiorno,
ho la schermata principale del mio programma e quando clicco su un pulsante della toolbar mi apre la form che voglio ma questa form contiene una combobox che all'apertura di esso viene popolata leggendo i dati da un DB access e questa form non viene caricata prima di 7 secondi perchè il DB è grande contiene circa 9000 record e quindi vorrei che prima di aprire la form mi carica un'altro form che alla fine è uno splash screen (contiene "Caricamento in corso" e una gif animata) e vorrei che durante il caricamento della form mi viene visualizzato e al momento che ha finito di popolare la combobox quindi alla visualizzazione della form lo splash screen si deve chiudere.
Ho provato molte cose ma niente mi apre solo lo splash screen e non finisce di caricare la form aiuto :help:
grazie in anticipo a tutti
Lo si può fare abbastanza facilmente giocando con My.Application.DoEvents(). Ad esempio, ho 3 Form :
-Form1
-FormAttesa
-Form2 ( che contiene una ComboBox "pesante" ) :
> Anzitutto, in un modulo :
Public FA As FormAttesa
Public F2 As Form2
> Form1 ( Click su pulsante per aprire Form2 ) :
FA = New FormAttesa
FA.Show()
F2 = New Form2
F2.Show()
> Form2 :
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ComboBox1.Enabled = False
For i As Integer = 1 To 500
ComboBox1.Items.Add("elemento_" & i)
System.Threading.Thread.Sleep(10)
My.Application.DoEvents()
Next
FA.Close()
ComboBox1.Enabled = True
End Sub
;)
Ciao Marco,
dopo provo ma con te vado a occhi chiusi :D senza di te sono perso hihihi
grazie ancora una volta :cool:
Ciao Marco,
ho provato ma non ci sono riuscito allora i primi due passi è come hai scritto tu il terzo per quando riguarda il form2 il mio è così:
Private Sub NuovoB_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
data.Value = Now.Date
CaricaSpedizione()
CaricaCitta()
System.Threading.Thread.Sleep(100)
My.Application.DoEvents()
frmAttesa.Close()
start = 1
End Sub
questa è la procedura caricacitta che va a riempire la combobox:
'Procedura per far per riempire la combobox citta
Public Sub CaricaCitta()
'***********************DATABASE***********************
Dim sql As String 'variabile dove memorizzo la stringa sql
'query
sql = "select * from dbo_Comuni_ISTAT order by Descrizione"
'effettuo la connessione al database ed eseguo la query memorizzando nella variabile
Dim objDataAdapter As New OleDbDataAdapter(sql, Cn1)
'crea il datatable
Dim objTable As New DataTable()
'inserisce i dati nel dataadapter
objDataAdapter.Fill(objTable)
citta.DataSource = objTable
citta.DisplayMember = "Descrizione"
citta.ValueMember = "Codice"
citta.Text = ""
If citta.Items.Count = 0 Then
ecitta.Enabled = False
Else
ecitta.Enabled = True
End If
'effettuo la connessione al database ed eseguo la query memorizzando nella variabile
Dim objDataAdapter1 As New OleDbDataAdapter(sql, Cn1)
'crea il datatable
Dim objTable1 As New DataTable()
'inserisce i dati nel dataadapter
objDataAdapter.Fill(objTable1)
cittaM.DataSource = objTable1
cittaM.DisplayMember = "Descrizione"
cittaM.ValueMember = "Codice"
cittaM.Text = ""
If cittaM.Items.Count = 0 Then
ecittam.Enabled = False
Else
ecittam.Enabled = True
End If
CalcolaCitta()
End Sub
funziona tutto solo che tra i due form non mi carica quello per l'attesa :help:
System.Threading.Thread.Sleep(10)
L'ho usato io nell'esempio per simulare un caricamento oneroso, nel tuo caso è inutile metterlo.
Inoltre, se usi quel sistema ovvio che non funziona. Tu usi un Adapter, perciò carichi i dati in un colpo solo, oltretutto in sola lettura un DataReader è più veloce. Usa un DataReader, poi, nel ciclo di lettura del DataReader ( inserimento delle città nella Combo una per volta ) inserisci il DoEvents()... ;)
Ciao Marco quindi dovrei fare questo:
Dim cmd As New OleDbCommand(sql, Cn1)
Dim dr As OleDbDataReader = cmd.ExecuteReader
Do While dr.Read()
citta.Items.Add(dr.Item("Descrizione"))
Loop
dr.Close()
Allora il primo problema è che il ciclo mi rimane in loop, il secondo come faccio ad assegnare anche il valore alla combobox?
ES. prima utilizzavo citta.ValueMember = "Codice"
utilizzavo citta.DataSource = objTable per l'autocomplete adesso come lo faccio?
scusa Marco se ti faccio queste domande ma il datareader a me non funziona mai come dovrebbe funzionare :D
Ciao Marco,
ho risolto così i miei problemi allora ho fatto la procedura carica città in questo modo:
Public Sub CaricaCitta()
'***********************DATABASE***********************
Dim sql As String 'variabile dove memorizzo la stringa sql
'query
sql = "select * from dbo_Comuni_ISTAT order by Descrizione"
'effettuo la connessione al database ed eseguo la query memorizzando nella variabile
Dim cmd As New OleDbCommand(sql, Cn1)
'inserisce il risultato nel datareader
Dim dr As OleDbDataReader
Dim Dati As ArrayList = New ArrayList()
Dim Dati1 As ArrayList = New ArrayList()
Try
dr = cmd.ExecuteReader()
While dr.Read
Dati.Add(New addValore(dr.Item("Descrizione"), dr.Item("Codice")))
Dati1.Add(New addValore(dr.Item("Descrizione"), dr.Item("Codice")))
'System.Threading.Thread.Sleep(100)
My.Application.DoEvents()
End While
frmAttesa.Close()
Catch e As Exception
MessageBox.Show("Errore: " + e.ToString)
Finally
cmd.Dispose()
dr.Close()
dr.Dispose()
End Try
citta.DataSource = Dati
citta.DisplayMember = "Display"
citta.ValueMember = "Value"
cittaM.DataSource = Dati1
cittaM.DisplayMember = "Display"
cittaM.ValueMember = "Value"
End Sub
dove addValore è una classe che contiene:
Public Class addValore
Private m_Display As String
Private m_Value As String
Public Sub New(ByVal Display As String, ByVal Value As String)
m_Display = Display
m_Value = Value
End Sub
Public ReadOnly Property Display() As String
Get
Return m_Display
End Get
End Property
Public ReadOnly Property Value() As String
Get
Return m_Value
End Get
End Property
End Class
così ho risolto i miei problemi che ti ho elengato prima però il form di attesa me lo fa vedere solo per 2 sec e non per il tempo che il programma ci mette a popolare le combobox come posso risolvere?
grazie in anticipo :D
Allora, non sono molto d'accordo con la tua soluzione : perchè usare 2 ArrayList d'appoggio ? Vediamo di sistemare il popolamento della Combo, poi pensiamo al discorso della splash d'attesa.
1. Come hai giustamente notato la ComboBox può gestire elenchi di Oggetti, quindi classi, a questo punto è inutile richiamare .ValueMember e .DisplayMember, e sono inutili ulteriori passaggi tra Reader e array di appoggio superflui :
...
...
Dim RDR As OleDb.OleDbDataReader = CMD.ExecuteReader()
While (RDR.Read())
ComboBox1.Items.Add(New ComboItem(RDR("campo1"), RDR("campo2")))
End While
RDR.Close()
...
...
2. ComboItem è la mia classe personalizzata per gestire gli oggetti della Combo ( la tua "addValore"... ) :
Public Class ComboItem
Private m_displayMember As String
Private m_valueMember As String
Public Sub New(ByVal dm As String, ByVal vm As String)
m_displayMember = dm
m_valueMember = vm
End Sub
Public Overrides Function ToString() As String
Return m_displayMember
End Function
Public Property DMember() As String
Get
Return m_displayMember
End Get
Set(ByVal value As String)
m_displayMember = value
End Set
End Property
Public Property VMember() As String
Get
Return m_valueMember
End Get
Set(ByVal value As String)
m_valueMember = value
End Set
End Property
End Class
Da notare che eseguendo l'Override di .ToString(), se vado ad aggiungere alla Combo l'oggetto con .Add(), la Combo "capirà" che il DisplayMember è "campo1".
3. Come faccio, a questo punto, dato che non ho settato il ValueMember della Combo, ad estrarlo su selezione dell'utente ? Semplice :
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
MsgBox(CType(ComboBox1.SelectedItem, ComboItem).VMember)
End Sub
;)
4. Infine, come già detto, basta che aggiungi un My.Application.DoEvents() nel ciclo di lettura del Reader, e, seguendo il mio esempio precedente, avrai la tua Form di attesa ! ;)
Ciao Marco,
ho provato e ho capito tutti gli errori anzi gli orrori :D che ho fatto in precedenza come hai detto tu funziona perfettamente. l'unica domanda che è rimasta adesso è facendo in questo modo cioè caricare la combobox 1 ad 1 ci mette più di 3 minuti a caricare la form mentre caricandoli tutti insieme come facevo in precedenza ci mette 10 secondi c'è un modo per velocizzare in questo modo?altrimenti mi conviene farla aprire dopo 10 secondi senza il form attesa che con il form attesa però dopo 3 minuti...aspetto tue risposte grazie ancora per la pasienza :D
Ciao Marco,
ho provato e ho capito tutti gli errori anzi gli orrori :D che ho fatto in precedenza come hai detto tu funziona perfettamente. l'unica domanda che è rimasta adesso è facendo in questo modo cioè caricare la combobox 1 ad 1 ci mette più di 3 minuti a caricare la form mentre caricandoli tutti insieme come facevo in precedenza ci mette 10 secondi c'è un modo per velocizzare in questo modo?altrimenti mi conviene farla aprire dopo 10 secondi senza il form attesa che con il form attesa però dopo 3 minuti...aspetto tue risposte grazie ancora per la pasienza :D
3 minuti ? :eek:
Mi pare strano, anche se ammetto che My.Application.DoEvents() in un ciclo appesantisce parecchio l'operazione...
In ogni caso, c'è sempre la possibilità di aprire la FormAttesa su un Thread separato ( e adesso che ci penso, forse la dovevo mettere come prima scelta... :fagiano: :p ).
In pratica :
> Modulo :
Public F2 As Form2
> Apertura Form2 :
F2 = New Form2
F2.Show()
> Form2 :
Public Class Form2
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim T As New System.Threading.Thread(AddressOf Metodi.MostraFormAttesa)
T.Start()
ComboBox1.Enabled = False
...
...
CODICE inserimento da DB a ComboBox
...
...
ComboBox1.Enabled = True
Metodi.ChiudiFormAttesa()
End Sub
End Class
A questo punto "CODICE inserimento da DB a ComboBox" può essere qualsiasi cosa, Adapter + DataSet, DataReader, ecc... E inoltre NON è più necessario il DoEvents() ! ;)
> Metodi, Classe statica che gestisce la FormAttesa :
Public Class Metodi
Private Sub New()
'Classe statica
End Sub
Private Shared FA As FormAttesa
Public Shared Sub MostraFormAttesa()
FA = New FormAttesa
Application.Run(FA)
End Sub
Public Shared Sub ChiudiFormAttesa()
FA.Chiudi()
End Sub
End Class
> FormAttesa :
Public Class FormAttesa
Private Delegate Sub DlgChiudiForm()
Public Sub Chiudi()
If Me.InvokeRequired Then
Dim C As New DlgChiudiForm(AddressOf Chiudi)
Me.Invoke(C)
Else
Me.Close()
End If
End Sub
End Class
Soluzione sicuramente più adattabile e valida della precedente. ;)
Prova con l'Adapter e anche col DataReader, e vedi quale va meglio...
Ciao Marco,
adesso funziona tutto perfettamente meno di 10 secondi e con il form di caricamento :D grazie davvero prima o poi dovrò farti un monumento :cool:
Ciao Marco,
scusami ancora un'ultima cosa io ho bisogno di far visualizzare il form in modalità showdialog. Se il form lo faccio avviare in questa modalità dopo la chiusura del thread quindi alla visualizzazione del form l'applicazione perde il focus cioè se ho delle finestre aperte il programma va dietro tutte le finestre. Se il form lo faccio partire senza quello d'attesa quindi senza thread non ho problemi il programma rimane con il focus e lo stesso se inserisco il form di attesa ma il secondo form lo avvio normalmente con show.Ho provato a inserire dei focus ma niente non funziona spero che puoi aiutarmi grazie :help:
Prova con .BringToFront sulla/sulle Form che desideri stiano in primo piano. ShowDialog non è sempre necessario...
Ciao Marco,
non funziona neanche con bringtofront e se lo metto alla chiusura del form di attesa si blocca su questo form e non mi apre il secondo. Ho notato anche che come parte il form di attesa il primo form perde il focus e se ci clicco con il mouse sul primo form al termine del form di attesa non si naascondono sotto le finestre ma rimane tutto in primo piano come vorrei io. grazie ancora marco spero che mi aiuterai :muro:
Ciao Marco,
non funziona neanche con bringtofront e se lo metto alla chiusura del form di attesa si blocca su questo form e non mi apre il secondo. Ho notato anche che come parte il form di attesa il primo form perde il focus e se ci clicco con il mouse sul primo form al termine del form di attesa non si naascondono sotto le finestre ma rimane tutto in primo piano come vorrei io. grazie ancora marco spero che mi aiuterai :muro:
Non ho chiaro cosa vuoi ottenere. Ma se pensi di avere il Focus su più Form contemporaneamente temo rimarrai deluso. In un'applicazione WinForms il Focus va automaticamente sull'ultimo Form aperto, e in ogni caso, un solo Form per volta ( e un solo controllo per volta sullo stesso Form ) può avere il Focus...
Non ho chiaro cosa vuoi ottenere. Ma se pensi di avere il Focus su più Form contemporaneamente temo rimarrai deluso. In un'applicazione WinForms il Focus va automaticamente sull'ultimo Form aperto, e in ogni caso, un solo Form per volta ( e un solo controllo per volta sullo stesso Form ) può avere il Focus...
allora io ho il mio form principale dove se clicco sul pulsante "nuovo" mi deve aprire il form di inserimento in modalità showdialog e l'applicazione rimane in primo piano. Se tra i due form inserisco il form di attesa al momento della chiusura di lui e dell'apertura del form nuovo l'applicazione passa in secondo piano quindi è come se si riduce ad icona. mentre se il form nuovo lo apro con il form d'attesa e in modalita show questo non accade vorrei solo che all'apertura del form nuovo in modalità showdialog l'applicazione non passa in secondo piano ma rimane in primo piano
allora io ho il mio form principale dove se clicco sul pulsante "nuovo" mi deve aprire il form di inserimento in modalità showdialog e l'applicazione rimane in primo piano. Se tra i due form inserisco il form di attesa al momento della chiusura di lui e dell'apertura del form nuovo l'applicazione passa in secondo piano quindi è come se si riduce ad icona. mentre se il form nuovo lo apro con il form d'attesa e in modalita show questo non accade vorrei solo che all'apertura del form nuovo in modalità showdialog l'applicazione non passa in secondo piano ma rimane in primo piano
E' vero, probabilmente a causa dell'apertura del FormAttesa in un thread separato, ma succede solo con ShowDialog... Strano comportamento. Comunque, prima di sbatterci la testa, perchè ti serve per forza uno ShowDialog ? Se è per disabilitare il Form chiamante basta fare un .Enabled = False e ripristinarlo sulla chiusura del Form2. Se è per passare un valore dalla Form2 al Form di partenza, può essere fatto tranquillamente senza ShowDialog...
ok marco grazie per i consigli cerco di trovare un'altra strada tipo quelle che mi hai suggerito grazie ancora :D
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.