Konuyu Oyla:
  • Derecelendirme: 0/5 - 0 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Excel secili satır
#11
Arkadaşlar Selection teriminden yürüyün derim

Microsoft der ki Selection.Adrress size seçili bloğu verir.

Eğer ctrl ile adımlı seçim varsa ilk adımı verir, belirleyeceğiniz aralıktaki her hücreyi dolaşıp ayrı ayrı if   in Selection diye sormak gerekiyormuş

Hatta bu deçim içerisinde resim, nesne vb için ayrı sorgu gerekiyor diye laf uzuyor. 

özet geçtim.
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif


Cevapla
#12
Bilgisayar başına geçmişken size bir örnek hazırladım. 

- Hem soruya cevap olsun, hem de hücrelerin Delphi cephesinden iki farklı şekilde ( CELL ve RANGE olarak) nasıl nitelendikleri konusunda fikir sahibi olunabilsin istedim. Idea

- Excel için öncelikle kurulu ve açık mı kontrolünden sonra

- Selection.Address ile CTRL basılı iken tek tek yapılan seçimleri seçim sırasına göre alıyor.

- Adres eğer bir RANGE aralık ise ( aşağıdaki ekranda uyguladığım $F$8:$H$9 buna bir örnektir) hücre adres bloğunu bileşenlerine ayırıp her birini ayrı birer hücreye CTRL basılmış gibi tekil sonuç döndürüyor.

- Function parametersinde aTip_Range_1_Cells_2_Value_3_ gibi açık anlaşılsın bir paramater ile 1,2 veya 3 ile hangi tipte sonuç almak istediğinizi belirtiyorsunuz. 

- Sonuç tablosu için hücre ayracı olarak varsayılan '|' şeklinde belirledim. Bu parametreye değer atamazsanız varsayılan olarak bu kabul edilir.  Siz tilda yıldız vs. ne isterseniz koyabilirsiniz.


...
...
...




Kullanımı :


..
...
....



Sonuçlar :
jz5dwlqhsgce2ft4cuoy.png

Kod:
4,5|9,5|6,6|6,5|6,8|8,6|8,7|8,8|9,6|9,7|9,8
$E$4|$E$9|$F$6|$E$6|$H$6|$F$8|$G$8|$H$8|$F$9|$G$9|$H$9
a|f|3|c|z|5||d|6||f
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif


Cevapla
#13
Bence sorulmak istenen, "tüm satır seçili olursa nasıl tespit edilebilir?"
Excelde satır numaralarını gösteren ilk sütuna basıldığında satırın komple seçili hale gelme olayı.

Not: @mrmarmanın çözümü bunu kapsıyor mudur bilmiyorum. Denemedim.
There's no place like 127.0.0.1
WWW
Cevapla
#14
selamlar bende zamanında excel ile bir şeyler yapmak için uğraşırken birkaç site bulmuştum
kimi biraz eski fakat belki içinden işe yarayan şeyler çıkabilir

Kardeş site linki
http://www.delphiturkiye.com/forum/viewt...c42348f6e0

http://edn.embarcadero.com/article/10126
http://edn.embarcadero.com/article/10127
http://edn.embarcadero.com/article/10128
http://edn.embarcadero.com/article/10129
http://edn.embarcadero.com/article/10130

http://delphiprogrammingdiary.blogspot.c...elphi.html
Bu dünyada kendine sakladığın bilgi ahirette işine yaramaz. 
Cevapla
#15
@SimaWB

Evet kapsıyor ama limitlemek lazım. Keza satırı seçince Selection.Columns.Count ile ilgili değer alınsa da 16384 hücre dolaşmak istemeyiz.  Idea

Şöyle bir limit koydum. Son parametreye bir şey yazılmazsa max. 100 tane sütuna bakıyor. Ama siz dilerseniz bu rakamı 200, 500, 1000 dilediğiniz kadar genişletebilirsiniz.

Adresleri ikiye böldük. $6:$6  şeklinde eşit ise satır seçilmiş olduğu anlaşılıyor. Birden fazla satır seçili ise $6:$8 şeklinde oluyor. İkiye böldüğümüz adres $ hariç sadece rakam ise satır seçilmiş demek. Bunun başına $A gibi bir değer eklemek adresi bütünlemek için kafidir. Idea


Uses ActiveX, ComObj;

Function SeciliHucreler( aTip_Range_1_Cells_2_Value_3_: Word; boolSadeceDoluHucreler:Boolean; aSeparator:Char='|'; aMaxCol: Integer = 100; aMaxRow: Integer = 100 ) : String;
  type      TAdresTipi  = ( aNone = 0, aTekHucre,      aHucreBlok,
                                       aSatirBoyunca,  aSutunBoyunca );
  type      TExcelAdres = record
    AdresTipi      : TAdresTipi;
    Adr1, Adr2     : String;
    x1, y1, x2, y2 : Integer;
  end;

  function  HucreAdresTipi( Excel:OleVariant; strHucreAdr: String; iMaxCol, iMaxRow:Integer ): TExcelAdres;
    function IcerikTipi_123( aText: String ) : Byte; // 1 String; 2 Numeric; 3 Mixed
    var
      boolStr,
      boolNum : Boolean;
      i : Integer;
    begin
      boolStr := False;
      boolNum := False;
      for i := 1 to length(aText) do begin
        if CharInSet( aText[i], ['1'..'9', '0'] )      then boolNum := True;
        if CharInSet( aText[i], ['a'..'z', 'A'..'Z'] ) then boolStr := True;
      end;
      if boolNum AND boolStr then Result := 3 // mixed
      else
      if boolNum then Result := 2 // numeric
      else Result := 1; // string
    end;
  var
    i : Integer;
  begin
    With Result do begin // Varsayılan
      AdresTipi := aNone;
      Adr1      := '';
      Adr2      := '';
      x1        := -1;
      y1        := -1;
      y2        := -1;
      x2        := -1;
    end;

    if Pos(':', strHucreAdr) > 0 then // Seçili Blok Aralık Hücreler
    begin
      // Blok Hücre ancak hangi tip. aHucreBlok, aSatirBoyunca, aSutunBoyunca
      // Parse edelim.
      Result.Adr1 := Copy(strHucreAdr, 1, Pos(':', strHucreAdr)-1);
            System.Delete(strHucreAdr, 1, Pos(':', strHucreAdr));
      Result.Adr2 := strHucreAdr;

      // Şimdi Tipi Anlayalım..
        Case IcerikTipi_123( Result.Adr1 ) of
        1: Result.AdresTipi := aSutunBoyunca; // String
        2: Result.AdresTipi := aSatirBoyunca; // Numeric
        3: Result.AdresTipi := aHucreBlok     // Mixed
        end; // case
    end else begin
      Result.AdresTipi := aTekHucre;
    end;

    case Result.AdresTipi of
    aTekHucre:      begin
                      Result.x1 := Excel.Range[ strHucreAdr ].Column;
                      Result.y1 := Excel.Range[ strHucreAdr ].Row;

                      Result.x2 := Excel.Range[ strHucreAdr ].Column;
                      Result.y2 := Excel.Range[ strHucreAdr ].Row;
                    end;
    aHucreBlok:     begin
                      Result.x1 := Excel.Range[ Result.Adr1 ].Column;
                      Result.y1 := Excel.Range[ Result.Adr1 ].Row;

                      Result.x2 := Excel.Range[ Result.Adr2 ].Column;
                      Result.y2 := Excel.Range[ Result.Adr2 ].Row;
                    end;
    aSatirBoyunca:  begin
                      Result.x1 := Excel.Range[ '$A' + Result.Adr1 ].Column;
                      Result.y1 := Excel.Range[ '$A' + Result.Adr1 ].Row;

                      Result.x2 := iMaxCol;
                      Result.y2 := Excel.Range[ '$A' + Result.Adr2 ].Row;
                    end;
    aSutunBoyunca:  begin
                      Result.x1 := Excel.Range[ Result.Adr1 + '$1' ].Column;
                      Result.y1 := Excel.Range[ Result.Adr1 + '$1' ].Row;

                      Result.x2 := Excel.Range[ Result.Adr2 + '$1' ].Column;
                      Result.y2 := iMaxRow;
                    end;

    end;
  end;

  function IsExcelActive: boolean;
  const ClassName = 'Excel.Application';
  var
    ClassID : TCLSID; // ActiveX
    Unknown : IUnknown;
    aExcel  : OleVariant;
  begin
    Result := False;
  // EXCEL için Önce Kurulu mu AND sonra Aktif mi Kontrolüdür.  //
    if    Succeeded(CLSIDFromProgID(PWideChar(WideString(ClassName)), ClassID))
      AND Succeeded(CLSIDFromProgID(PWideChar(WideString(ClassName)), ClassID))
    then Result := Succeeded(GetActiveObject(ClassID, nil, Unknown));

    // Hafızada Excel kırıntısı kalmışsa onu test edelim.. "Access Violation" savar...
    if Result then
    begin
      aExcel := GetActiveOleObject('Excel.Application');
      Result := (aExcel.Workbooks.Count > 0) AND ( aExcel.WorkSheets.Count > 0 );
      aExcel := Unassigned;
    end;
  end;
Var
  aExcel        : OleVariant;
  aRange        : OleVariant;
  aExcelAddress : TExcelAdres;
  strHucreler,
  strHucreAdr,
  strHucreValue,
  strResult  : String;
  i, j       : Integer;
begin
  if IsExcelActive() then
  begin // Excel Kurulu ve şu an Açık
    aExcel := GetActiveOleObject('Excel.Application');
    try
      strHucreler := VarToStr( aExcel.Selection.Address );
      if strHucreler <> '' then
      begin
        strHucreler := strHucreler + ',';
        while pos(',', strHucreler) > 0 do
        begin
          strHucreAdr   := Trim( Copy(strHucreler, 1, Pos(',', strHucreler)-1 ) );

          aExcelAddress := HucreAdresTipi( aExcel, strHucreAdr, aMaxCol, aMaxRow );
          case aExcelAddress.AdresTipi of
          aTekHucre :
            begin
              strHucreValue := aExcel.Range[ strHucreAdr ].Text;
              Case aTip_Range_1_Cells_2_Value_3_ of
              1: strResult := Format('%s,%s', [ aExcel.Range[ strHucreAdr ].Row,
                                                aExcel.Range[ strHucreAdr ].Column ]);
              2: strResult := strHucreAdr;
              3: strResult := strHucreValue;
              end;

              if boolSadeceDoluHucreler then
              begin
                if Trim(strHucreValue) <> '' then
                begin
                  if Result = ''
                    then Result := strResult
                    else Result := Result + aSeparator + strResult;
                end;
              end
              else begin
                if Result = ''
                  then Result := strResult
                  else Result := Result + aSeparator + strResult;
              end;
            end;
          aHucreBlok, aSatirBoyunca, aSutunBoyunca :
            begin
              // Hücreleri dolaşıyoruz...
              i := aExcelAddress.y1;
              while i <= aExcelAddress.y2 do
              begin
                j := aExcelAddress.x1;
                while j <= aExcelAddress.x2 do
                begin
                  strHucreValue := aExcel.Cells[ i, j ].Text;
                  Case aTip_Range_1_Cells_2_Value_3_ of
                  1: strResult := Format('%d,%d', [i,j]);
                  2: strResult := aExcel.Cells[ i, j ].Address;
                  3: strResult := strHucreValue;
                  end;

                  if boolSadeceDoluHucreler then
                  begin
                    if Trim(strHucreValue) <> '' then
                    begin
                      if Result = ''
                        then Result := strResult
                        else Result := Result + aSeparator + strResult;
                    end;
                  end
                  else begin
                    if Result = ''
                      then Result := strResult
                      else Result := Result + aSeparator + strResult;
                  end;
                  inc(j);
                end;
                inc(i);
              end;
            end;
          end; // Case
          System.Delete( strHucreler, 1, Pos(',', strHucreler));
        end; // While

      end;
    finally
      aExcel := Unassigned;
    end;
  end else Exit;
end;



Yeni Kullanım Şekli.


procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  Memo1.Lines.Add( SeciliHucreler( 1, True, '|', 100, 100 ) );
  Memo1.Lines.Add( SeciliHucreler( 2, True, '|', 100, 100 ) );
  Memo1.Lines.Add( SeciliHucreler( 3, True, '|', 100, 100 ) );
end;


Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif


Cevapla
#16
Teşekkürümü ifade etmek için söz bulamadım. Allah razı olsun, ne dilerseniz dileyin, Allah gönlünüze göre versin.
Cevapla
#17
@ahmetb

Bu ve benzer konular kendi kendimize meydan okuma (challenge) tipinde, normal hayatta ihtiyacımız olmasa da içinden bir ders çıkarmak adına keyif aldığım bir konu oldu.

Ben teşekkür ederim. Ben de çözüm adına kod arşivime yeni bir burç eklemiş oldum.
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif


Cevapla
#18
(28-02-2019, Saat: 17:49)mrmarman Adlı Kullanıcıdan Alıntı: @SimaWB

Evet kapsıyor ama limitlemek lazım. Keza satırı seçince Selection.Columns.Count ile ilgili değer alınsa da 16384 hücre dolaşmak istemeyiz.  Idea

Şöyle bir limit koydum. Son parametreye bir şey yazılmazsa max. 100 tane sütuna bakıyor. Ama siz dilerseniz bu rakamı 200, 500, 1000 dilediğiniz kadar genişletebilirsiniz.

Adresleri ikiye böldük. $6:$6  şeklinde eşit ise satır seçilmiş olduğu anlaşılıyor. Birden fazla satır seçili ise $6:$8 şeklinde oluyor. İkiye böldüğümüz adres $ hariç sadece rakam ise satır seçilmiş demek. Bunun başına $A gibi bir değer eklemek adresi bütünlemek için kafidir. Idea


Uses ActiveX, ComObj;

Function SeciliHucreler( aTip_Range_1_Cells_2_Value_3_: Word; boolSadeceDoluHucreler:Boolean; aSeparator:Char='|'; aMaxCol: Integer = 100; aMaxRow: Integer = 100 ) : String;
  type      TAdresTipi  = ( aNone = 0, aTekHucre,      aHucreBlok,
                                       aSatirBoyunca,  aSutunBoyunca );
  type      TExcelAdres = record
    AdresTipi      : TAdresTipi;
    Adr1, Adr2     : String;
    x1, y1, x2, y2 : Integer;
  end;

  function  HucreAdresTipi( Excel:OleVariant; strHucreAdr: String; iMaxCol, iMaxRow:Integer ): TExcelAdres;
    function IcerikTipi_123( aText: String ) : Byte; // 1 String; 2 Numeric; 3 Mixed
    var
      boolStr,
      boolNum : Boolean;
      i : Integer;
    begin
      boolStr := False;
      boolNum := False;
      for i := 1 to length(aText) do begin
        if CharInSet( aText[i], ['1'..'9', '0'] )      then boolNum := True;
        if CharInSet( aText[i], ['a'..'z', 'A'..'Z'] ) then boolStr := True;
      end;
      if boolNum AND boolStr then Result := 3 // mixed
      else
      if boolNum then Result := 2 // numeric
      else Result := 1; // string
    end;
  var
    i : Integer;
  begin
    With Result do begin // Varsayılan
      AdresTipi := aNone;
      Adr1      := '';
      Adr2      := '';
      x1        := -1;
      y1        := -1;
      y2        := -1;
      x2        := -1;
    end;

    if Pos(':', strHucreAdr) > 0 then // Seçili Blok Aralık Hücreler
    begin
      // Blok Hücre ancak hangi tip. aHucreBlok, aSatirBoyunca, aSutunBoyunca
      // Parse edelim.
      Result.Adr1 := Copy(strHucreAdr, 1, Pos(':', strHucreAdr)-1);
            System.Delete(strHucreAdr, 1, Pos(':', strHucreAdr));
      Result.Adr2 := strHucreAdr;

      // Şimdi Tipi Anlayalım..
        Case IcerikTipi_123( Result.Adr1 ) of
        1: Result.AdresTipi := aSutunBoyunca; // String
        2: Result.AdresTipi := aSatirBoyunca; // Numeric
        3: Result.AdresTipi := aHucreBlok     // Mixed
        end; // case
    end else begin
      Result.AdresTipi := aTekHucre;
    end;

    case Result.AdresTipi of
    aTekHucre:      begin
                      Result.x1 := Excel.Range[ strHucreAdr ].Column;
                      Result.y1 := Excel.Range[ strHucreAdr ].Row;

                      Result.x2 := Excel.Range[ strHucreAdr ].Column;
                      Result.y2 := Excel.Range[ strHucreAdr ].Row;
                    end;
    aHucreBlok:     begin
                      Result.x1 := Excel.Range[ Result.Adr1 ].Column;
                      Result.y1 := Excel.Range[ Result.Adr1 ].Row;

                      Result.x2 := Excel.Range[ Result.Adr2 ].Column;
                      Result.y2 := Excel.Range[ Result.Adr2 ].Row;
                    end;
    aSatirBoyunca:  begin
                      Result.x1 := Excel.Range[ '$A' + Result.Adr1 ].Column;
                      Result.y1 := Excel.Range[ '$A' + Result.Adr1 ].Row;

                      Result.x2 := iMaxCol;
                      Result.y2 := Excel.Range[ '$A' + Result.Adr2 ].Row;
                    end;
    aSutunBoyunca:  begin
                      Result.x1 := Excel.Range[ Result.Adr1 + '$1' ].Column;
                      Result.y1 := Excel.Range[ Result.Adr1 + '$1' ].Row;

                      Result.x2 := Excel.Range[ Result.Adr2 + '$1' ].Column;
                      Result.y2 := iMaxRow;
                    end;

    end;
  end;

  function IsExcelActive: boolean;
  const ClassName = 'Excel.Application';
  var
    ClassID : TCLSID; // ActiveX
    Unknown : IUnknown;
    aExcel  : OleVariant;
  begin
    Result := False;
  // EXCEL için Önce Kurulu mu AND sonra Aktif mi Kontrolüdür.  //
    if    Succeeded(CLSIDFromProgID(PWideChar(WideString(ClassName)), ClassID))
      AND Succeeded(CLSIDFromProgID(PWideChar(WideString(ClassName)), ClassID))
    then Result := Succeeded(GetActiveObject(ClassID, nil, Unknown));

    // Hafızada Excel kırıntısı kalmışsa onu test edelim.. "Access Violation" savar...
    if Result then
    begin
      aExcel := GetActiveOleObject('Excel.Application');
      Result := (aExcel.Workbooks.Count > 0) AND ( aExcel.WorkSheets.Count > 0 );
      aExcel := Unassigned;
    end;
  end;
Var
  aExcel        : OleVariant;
  aRange        : OleVariant;
  aExcelAddress : TExcelAdres;
  strHucreler,
  strHucreAdr,
  strHucreValue,
  strResult  : String;
  i, j       : Integer;
begin
  if IsExcelActive() then
  begin // Excel Kurulu ve şu an Açık
    aExcel := GetActiveOleObject('Excel.Application');
    try
      strHucreler := VarToStr( aExcel.Selection.Address );
      if strHucreler <> '' then
      begin
        strHucreler := strHucreler + ',';
        while pos(',', strHucreler) > 0 do
        begin
          strHucreAdr   := Trim( Copy(strHucreler, 1, Pos(',', strHucreler)-1 ) );

          aExcelAddress := HucreAdresTipi( aExcel, strHucreAdr, aMaxCol, aMaxRow );
          case aExcelAddress.AdresTipi of
          aTekHucre :
            begin
              strHucreValue := aExcel.Range[ strHucreAdr ].Text;
              Case aTip_Range_1_Cells_2_Value_3_ of
              1: strResult := Format('%s,%s', [ aExcel.Range[ strHucreAdr ].Row,
                                                aExcel.Range[ strHucreAdr ].Column ]);
              2: strResult := strHucreAdr;
              3: strResult := strHucreValue;
              end;

              if boolSadeceDoluHucreler then
              begin
                if Trim(strHucreValue) <> '' then
                begin
                  if Result = ''
                    then Result := strResult
                    else Result := Result + aSeparator + strResult;
                end;
              end
              else begin
                if Result = ''
                  then Result := strResult
                  else Result := Result + aSeparator + strResult;
              end;
            end;
          aHucreBlok, aSatirBoyunca, aSutunBoyunca :
            begin
              // Hücreleri dolaşıyoruz...
              i := aExcelAddress.y1;
              while i <= aExcelAddress.y2 do
              begin
                j := aExcelAddress.x1;
                while j <= aExcelAddress.x2 do
                begin
                  strHucreValue := aExcel.Cells[ i, j ].Text;
                  Case aTip_Range_1_Cells_2_Value_3_ of
                  1: strResult := Format('%d,%d', [i,j]);
                  2: strResult := aExcel.Cells[ i, j ].Address;
                  3: strResult := strHucreValue;
                  end;

                  if boolSadeceDoluHucreler then
                  begin
                    if Trim(strHucreValue) <> '' then
                    begin
                      if Result = ''
                        then Result := strResult
                        else Result := Result + aSeparator + strResult;
                    end;
                  end
                  else begin
                    if Result = ''
                      then Result := strResult
                      else Result := Result + aSeparator + strResult;
                  end;
                  inc(j);
                end;
                inc(i);
              end;
            end;
          end; // Case
          System.Delete( strHucreler, 1, Pos(',', strHucreler));
        end; // While

      end;
    finally
      aExcel := Unassigned;
    end;
  end else Exit;
end;



Yeni Kullanım Şekli.


procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  Memo1.Lines.Add( SeciliHucreler( 1, True, '|', 100, 100 ) );
  Memo1.Lines.Add( SeciliHucreler( 2, True, '|', 100, 100 ) );
  Memo1.Lines.Add( SeciliHucreler( 3, True, '|', 100, 100 ) );
end;



(01-03-2019, Saat: 19:17)mrmarman Adlı Kullanıcıdan Alıntı: @ahmetb

Bu ve benzer konular kendi kendimize meydan okuma (challenge) tipinde, normal hayatta ihtiyacımız olmasa da içinden bir ders çıkarmak adına keyif aldığım bir konu oldu.

Ben teşekkür ederim. Ben de çözüm adına kod arşivime yeni bir burç eklemiş oldum.



Merhaba; İçinden çıkamadım bir sorunu var. Yardımınızı rica ederim.


  
Memo1.Lines.Add(SeciliHucreler(3, True, '|', 100, 100));

Add satır alt, alta eklemesi lazımken memoya yan, yana ekliyor. Bu durum normal mi?

A 045|A 348|A 345|A 346|A 049|A 045
Cevapla
#19
normal,
amaç: o satırı bir stringlist'in DelimitedText property'sine atayıp, separator ile DELIMITER belirtip otomatik satırlara dönüşmesini sağlamaktır.

bkz. 

var
SL: TStringList;
begin
SL := TStringList.Create;
try
  SL.Delimiter := '|';
  SL.DelimitedText := HucreAdresMemoyaEklenenSatir; 
// bu aşamada SL[0] içinde A 045, SL[1] içinde A 348 vs. vs. göreceksiniz.   
// burada iş bitince de finally free olacak.    
finally
  SL.Free;
end;

Dilerseniz kendiniz de parse edebilirsiniz.
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif


Cevapla
#20
Haklısınız, Ben başka yerden yakaladım kodları.


                   
  if Trim(strHucreValue) <> '' then
                      begin
                        if Result = '' then
                          Result := strResult
                        else
                          Result := Result + aSeparator + strResult;
                        Yakala.Add(strResult);
                      end;
Cevapla


Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  DBLookupComboBox'da istenilen kayıt seçili gelsin OZCANK 7 379 30-01-2019, Saat: 21:09
Son Yorum: OZCANK
  Excel den Delphi ye veri çekme nmtsltn 1 343 26-12-2018, Saat: 11:32
Son Yorum: DelphiCan Yönetim
  Excel Export PDF pro_imaj 16 6.862 04-07-2018, Saat: 18:21
Son Yorum: pro_imaj
  Excel, PDF ve Yazıcı formu Component 3ddark 8 780 22-06-2018, Saat: 14:46
Son Yorum: edo
  [ÇÖZÜLDÜ]-cxDBPivotGrid Seçili Satır Alan Değeri Alma hi_selamlar 2 516 21-06-2018, Saat: 10:40
Son Yorum: hi_selamlar



Konuyu Okuyanlar: 1 Ziyaretçi