TBitmap No Safe Thread Sorunu - Baskı Önizleme +- Delphi Can (https://www.delphican.com) +-- Forum: Delphi (https://www.delphican.com/forumdisplay.php?fid=3) +--- Forum: Mobil Platform - FireMonkey (FMX) (https://www.delphican.com/forumdisplay.php?fid=7) +--- Konu Başlığı: TBitmap No Safe Thread Sorunu (/showthread.php?tid=846) |
TBitmap No Safe Thread Sorunu - codder71 - 05-04-2017 Merhaba Arkadaşlar Uzun zamandır üzerinde çalıştığım uygulamam için bir dosya yönetici yapmaktayım. Kullanıcıya kolaylık sağlamak için Thumbnail tarzı bir yapı üzerinde çalışıyorum. Bunu sağlamak içinde TBitmap class'ını kullanmak istedim yalnız bu nesneyi thread içinde kullandığım zaman uygulama işlem sırasında kapanıyor. Araştırmam sonucu no safe thread olduğunu farkettim ve yabancı formlarda da bu tarz sorular geldiğinide gördüm ve bi kaçta örnek buldum ama sonuç alamadım. Sizce bu durumda ne yapmam lazım. Safe Thread olan başka bir yöntem var mı ? yada TBitmap Nesnesini safe thread kullanmanın bir yolu varmı ? Yardımlarınız bekliyorum. Şimdiden cevaplarınız için teşekkürler ederim. Cvp: TBitmap No Safe Thread Sorunu - Tuğrul HELVACI - 05-04-2017 (05-04-2017, Saat: 14:09)codder71 Adlı Kullanıcıdan Alıntı: Merhaba Arkadaşlar Aynı TBitmap nesnesini ve aynı dosyayı ortak kullanacak thread'ler yok ise istediğinizi yapabilmeniz biraz daha kolaylaşıyor. Öncelikle thread içinde ilgili dosyadan okumanızı yapıp local bir TBitmap instance'ına doldurabilirsiniz resmi. İşin sıkıntılı kısmı ile VCL nesneleri ile çalışırken karşılaşacaksınız. TImage.Picture.Assign gibi bir işlem yapıyor olacaksınız sanırım. Bu durumda da senkronizasyon sağlamanız gerekecek. Bunun için de TThread.Queue kullanmanız yerinde olabilir. Aslına bakarsanız önce siz bir girişimde bulunun bir şeyler yapın, yaptıklarınızı da paylaşın. Sonra sıkıntılara ortak bir çözüm bulunur burada. Cvp: TBitmap No Safe Thread Sorunu - codder71 - 05-04-2017 (05-04-2017, Saat: 14:39)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı:Merhabalar(05-04-2017, Saat: 14:09)codder71 Adlı Kullanıcıdan Alıntı: Merhaba Arkadaşlar Hocam öncelikle cevabınız için teşekkür ederim. Hocam aslında yapmak istediğim basit bir işlem bir listview'im var bunla cihazdaki dosyalar listeliyorum ve dosya türüne göre uygulamanın içine gömdüğüm simgeleri listview bitmapa bağlıyorum. Sadece image türündeki listelenen dosyaları Thumbnail gibi küçük simgeler halinde listview kenarına almak istiyorum. Hocam şuan için örnek kodlarımı ekleyemeyeceğim çünkü evde değilim ama akşam eve geçtiğim zaman kodları da yüklerim. Cvp: TBitmap No Safe Thread Sorunu - codder71 - 05-04-2017 Hocam kullandığım kodları paylaşıyorum. Resim thread kodları : constructor TResimKucult.create(yol : string); begin FreeOnTerminate:=true; isim:=yol; inherited Create (False); end; procedure TResimKucult.bagla; var index:integer; begin index:=form4.ListBox3.Items.IndexOf(ExtractFileName(isim)); form4.ListView1.Items[index].Bitmap:=resim; end; procedure TResimKucult.Execute; begin inherited; try resim := TBitmap.CreateFromFile(isim); Synchronize(bagla); while not Terminated do begin Sleep(100); end; resim.Free; except on E:Exception do begin Log.d('Thread Hatası: ' + E.message); end; end; end; Tetiklediğim Bölüm : . . . . . end else if (Dosya_uzantisi = '.jpg') or (Dosya_uzantisi = '.jpeg') or (Dosya_uzantisi = '.tiff') //Buraya Küçük Resimler Eklenecek or (Dosya_uzantisi = '.gif') or (Dosya_uzantisi = '.bmp') or (Dosya_uzantisi = '.psd') or (Dosya_uzantisi = '.eps') or (Dosya_uzantisi = '.raw') or (Dosya_uzantisi = '.tif') or (Dosya_uzantisi = '.png') then begin Synchronize(image); TResimKucult.create(dosya_yolu); end else . . Hocam threadın adından da anlaşılacağı gibi önce imageleri küçültmeye çalıştım ama hiç bir şekilde olmadı zaten olayın threaden kaynaklandığını öğrenince başka şeyler denedim. Cvp: TBitmap No Safe Thread Sorunu - Tuğrul HELVACI - 06-04-2017 Gördüğüm kadarı ile thread kodlarınızda sıkıntı var. FMX'e nispeten aşina olmamakla birlikte, Bagla metodunuzun içindeki kodun ..Bitmap := ... yerine; ..Bitmap.Assign biçiminde olması gerektiğini düşünüyorum. Ayrıca, Sycnhronize ile çağrım yaptığınız için aslında yapmış olduğunuz iş ana thread'de yapılıyor demektir. Queue kullanabilirsiniz, biraz daha efektif olur. Ayrıca neden while not Terminated döngüsü içinde 100 milisaniye beklediğinizi anlamadım. Synchronize, Queue vb şeylerle uğraşmayayım daha basit halledeyim derseniz eğer, TResimKucult.Execute içinde bir TBitmap yerel değişkeni tanımlayın, bunu Create edin, dosyadan içine resim yükleyin, ardından PostMessage(Formunuz.Handle, WM_RESIM_YUKLENDI, 0, NativeInt(ABitmap)); yolu ile de ana thread'in kuyruğuna bir veri gönderebilirsiniz. Kısaca; const WM_RESIM_YUKLENDI = WM_USER + $1234; type TForm1 = class(TForm) private procedure WMResimYuklendi(var Message : TMessage); message WM_RESIM_YUKLENDI; public end; procedure TForm1.WMResimYuklendi(var Message: TMessage); var ABitmap : TBitmap; begin if Pointer(Message.LParam) <> nil then begin ABitmap := TBitmap(Message.LParam); try // Burada ListBox'ın ilgili itemine resmi atayabilirsiniz. // Assign ile atamanızı tavsiye ederim. finally ABitmap.Free; end; end; end; TThread.CreateAnonymousThread( procedure var ABitmap : TBitmap; begin ABitmap := TBitmap.Create; ABitmap.LoadFromFile('Dosyaniz.bmp'); PostMessage(Form1.Handle, WM_RESIM_YUKLENDI, 0, NativeInt(ABitmap)); // Bu noktada ABitmap'ı Free etmiyoruz buraya dikkat.! end ).Start; gibi bir kullanımınız olabilir. Sorun yaşadığınız bir husus olur ise bu konu üzerinden yazışmaya devam ederiz. Cvp: TBitmap No Safe Thread Sorunu - codder71 - 06-04-2017 (06-04-2017, Saat: 14:41)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Gördüğüm kadarı ile thread kodlarınızda sıkıntı var. FMX'e nispeten aşina olmamakla birlikte, Bagla metodunuzun içindeki kodun ..Bitmap := ... yerine; ..Bitmap.Assign biçiminde olması gerektiğini düşünüyorum. Ayrıca, Sycnhronize ile çağrım yaptığınız için aslında yapmış olduğunuz iş ana thread'de yapılıyor demektir. Queue kullanabilirsiniz, biraz daha efektif olur. Merhabalar Hocam bu örnekte verdiğim kodu stackowerflowdan aldım. Orda soruyu soran kişi sorunu bu şekilde çözmüş olduğunu söyledi aslında o while kodunu neden koyduğunu bende anlamadım. Düzenlediğiniz kodları denedim yalnız hatalar alıyorum. Bu kısım tanımlanamıyor. Ayrıca Delphi Androidde Postmessage kullanılabiliyor mu onu bilmiyorum. PostMessage(Form1.Handle, WM_RESIM_YUKLENDI, 0, NativeInt(ABitmap)); Bu kısımda ise WM_USER ve TMessage kısımları tanımlanamıyor. WM_RESIM_YUKLENDI = WM_USER + $1234; procedure WMResimYuklendi(var Message : TMessage); message WM_RESIM_YUKLENDI; Ayrıca hocam bu TThread.CreateAnonymousThread şeklinde thread tanımlayıp içinde Tbitmap oluşturmuşsunuz ben bunu denedim yalnız bu şekilde de deneme yaptığımız zaman yine hata alıyorum uygulama cihazda işlem sırasında kapanıyor. Delphi 7de TBitmap Safe Threaddi neden bunu fmx de no safe thread yaptılar anlamış değilim. Cvp: TBitmap No Safe Thread Sorunu - Tuğrul HELVACI - 06-04-2017 (06-04-2017, Saat: 15:49)codder71 Adlı Kullanıcıdan Alıntı:(06-04-2017, Saat: 14:41)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Gördüğüm kadarı ile thread kodlarınızda sıkıntı var. FMX'e nispeten aşina olmamakla birlikte, Bagla metodunuzun içindeki kodun ..Bitmap := ... yerine; ..Bitmap.Assign biçiminde olması gerektiğini düşünüyorum. Ayrıca, Sycnhronize ile çağrım yaptığınız için aslında yapmış olduğunuz iş ana thread'de yapılıyor demektir. Queue kullanabilirsiniz, biraz daha efektif olur. Uygulamanızın Android olduğunu söylemediğiniz için bu şekilde bir örnek vermiştim. Android ise tabii PostMessage ile yapamayacaksınız. Bu durumda PostMessage gördüğünüz yerde TThread.Queue kullanmanız aynı etkiyi almanız için yeterli olur. Evet anonim bir thread içinde bir bitmap oluşturdum ve yükleme işini orada yaptım. Siz kodunuzu TThread.Queue haline getirmeye çalışın bir deneme uygulamasında, sonra bir hata alır iseniz adım adım yardımcı olmaya çalışalım. Cvp: TBitmap No Safe Thread Sorunu - AliZairov - 06-04-2017 (05-04-2017, Saat: 14:09)codder71 Adlı Kullanıcıdan Alıntı: Merhaba Arkadaşlarİyi akşamlar. Ben bu konuda arkadaşların yardımı ile netden kasmadan resim indirip asenkron bir şekilde listede gösteriyordum. Kodlara bakın belki işinize yarıya bilir. FMX için kullanmıştım. Win, Mac ve Android için kullanıyorum bunu. Cvp: TBitmap No Safe Thread Sorunu - codder71 - 07-04-2017 (06-04-2017, Saat: 22:51)AliZairov Adlı Kullanıcıdan Alıntı:(05-04-2017, Saat: 14:09)codder71 Adlı Kullanıcıdan Alıntı: Merhaba Arkadaşlarİyi akşamlar. Ben bu konuda arkadaşların yardımı ile netden kasmadan resim indirip asenkron bir şekilde listede gösteriyordum. Kodlara bakın belki işinize yarıya bilir. FMX için kullanmıştım. Win, Mac ve Android için kullanıyorum bunu. Merhabalar Cevabınız için çok teşekkür ederim. Kodları kendime göre uyarladım uygulamanın kapanmasını önledim yalnız uygulamanın kasmasının önüne geçemedim maalesef. Kodları paylaşıyorum. constructor TResimKucult.create(yol: string); begin FreeOnTerminate := true; isim := yol; inherited create(False); end; procedure TResimKucult.Execute; var ms: TMemoryStream; index: integer; begin ms := TMemoryStream.create; ms.LoadFromFile(isim); TThread.Synchronize(TThread.CurrentThread, procedure() var resim: TBitmap; begin resim := TBitmap.CreateFromStream(ms); resim.Resize(resim.Width div 100, resim.Height div 100); // Resmi resize yaptığım zaman uygulama kapanmıyor. index := form4.ListBox3.Items.IndexOf(ExtractFileName(isim)); form4.ListView1.Items[index].Bitmap.Assign(resim); resim.Free; end); ms.Free; Sleep(0); end; Cvp: TBitmap No Safe Thread Sorunu - codder71 - 08-04-2017 (06-04-2017, Saat: 16:43)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı:Merhabalar(06-04-2017, Saat: 15:49)codder71 Adlı Kullanıcıdan Alıntı: Merhabalar TThread.Queue ilgili şöyle bir deneme yaptım uygulamada kasma yok ama nedense resimlerde yüklenmiyor. Sebebi nedir acaba ?? constructor TResimKucult.create(yol : string); begin FreeOnTerminate:=true; isim:=yol; inherited Create (False); end; procedure TResimKucult.bagla; var resim:TBitmap; index:integer; begin resim:=TBitmap.Create; resim.LoadFromFile(isim); index:=form4.ListBox3.Items.IndexOf(ExtractFileName(isim)); form4.ListView1.Items[index].Bitmap.Assign(resim); resim.Free; end; procedure TResimKucult.Execute; begin Queue(nil,bagla); end; |